soturail 0.4.1 → 0.7.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.
Files changed (165) hide show
  1. package/LICENSE +15 -21
  2. package/README.md +292 -157
  3. package/dist/cli.js +12 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/agents.js +39 -5
  6. package/dist/commands/agents.js.map +1 -1
  7. package/dist/commands/context.js +66 -2
  8. package/dist/commands/context.js.map +1 -1
  9. package/dist/commands/diagram.d.ts +2 -0
  10. package/dist/commands/diagram.js +24 -0
  11. package/dist/commands/diagram.js.map +1 -0
  12. package/dist/commands/eval.d.ts +2 -0
  13. package/dist/commands/eval.js +25 -0
  14. package/dist/commands/eval.js.map +1 -0
  15. package/dist/commands/format.js +14 -4
  16. package/dist/commands/format.js.map +1 -1
  17. package/dist/commands/fs.d.ts +2 -0
  18. package/dist/commands/fs.js +19 -0
  19. package/dist/commands/fs.js.map +1 -0
  20. package/dist/commands/harness.d.ts +2 -0
  21. package/dist/commands/harness.js +35 -0
  22. package/dist/commands/harness.js.map +1 -0
  23. package/dist/commands/mcp.js +5 -0
  24. package/dist/commands/mcp.js.map +1 -1
  25. package/dist/commands/memory.js +40 -0
  26. package/dist/commands/memory.js.map +1 -1
  27. package/dist/commands/native.js +4 -0
  28. package/dist/commands/native.js.map +1 -1
  29. package/dist/commands/policy.d.ts +2 -0
  30. package/dist/commands/policy.js +25 -0
  31. package/dist/commands/policy.js.map +1 -0
  32. package/dist/commands/release.js +9 -2
  33. package/dist/commands/release.js.map +1 -1
  34. package/dist/commands/run.js +15 -3
  35. package/dist/commands/run.js.map +1 -1
  36. package/dist/commands/skills.js +15 -0
  37. package/dist/commands/skills.js.map +1 -1
  38. package/dist/commands/validate.d.ts +2 -0
  39. package/dist/commands/validate.js +13 -0
  40. package/dist/commands/validate.js.map +1 -0
  41. package/dist/commands/workflow.js +35 -5
  42. package/dist/commands/workflow.js.map +1 -1
  43. package/dist/core/agent-docs-hygiene.d.ts +3 -0
  44. package/dist/core/agent-docs-hygiene.js +83 -0
  45. package/dist/core/agent-docs-hygiene.js.map +1 -0
  46. package/dist/core/agent-exporter.d.ts +3 -1
  47. package/dist/core/agent-exporter.js +136 -12
  48. package/dist/core/agent-exporter.js.map +1 -1
  49. package/dist/core/agent-profile.d.ts +1 -1
  50. package/dist/core/agent-registry.js +60 -0
  51. package/dist/core/agent-registry.js.map +1 -1
  52. package/dist/core/agent-runtime.d.ts +57 -0
  53. package/dist/core/agent-runtime.js +371 -0
  54. package/dist/core/agent-runtime.js.map +1 -0
  55. package/dist/core/config.d.ts +20 -0
  56. package/dist/core/config.js +39 -2
  57. package/dist/core/config.js.map +1 -1
  58. package/dist/core/context-intelligence.d.ts +47 -0
  59. package/dist/core/context-intelligence.js +283 -0
  60. package/dist/core/context-intelligence.js.map +1 -0
  61. package/dist/core/diagram-rail.d.ts +31 -0
  62. package/dist/core/diagram-rail.js +235 -0
  63. package/dist/core/diagram-rail.js.map +1 -0
  64. package/dist/core/diagram-validator.d.ts +10 -0
  65. package/dist/core/diagram-validator.js +53 -0
  66. package/dist/core/diagram-validator.js.map +1 -0
  67. package/dist/core/evaluation-suite.d.ts +28 -0
  68. package/dist/core/evaluation-suite.js +333 -0
  69. package/dist/core/evaluation-suite.js.map +1 -0
  70. package/dist/core/evidence-pack.d.ts +4 -0
  71. package/dist/core/evidence-pack.js +139 -0
  72. package/dist/core/evidence-pack.js.map +1 -0
  73. package/dist/core/format-compare.d.ts +12 -0
  74. package/dist/core/format-compare.js +68 -0
  75. package/dist/core/format-compare.js.map +1 -0
  76. package/dist/core/fs-evidence.d.ts +25 -0
  77. package/dist/core/fs-evidence.js +96 -0
  78. package/dist/core/fs-evidence.js.map +1 -0
  79. package/dist/core/harness-rail.d.ts +34 -0
  80. package/dist/core/harness-rail.js +158 -0
  81. package/dist/core/harness-rail.js.map +1 -0
  82. package/dist/core/json-validator.d.ts +24 -0
  83. package/dist/core/json-validator.js +138 -0
  84. package/dist/core/json-validator.js.map +1 -0
  85. package/dist/core/mcp-exposure.d.ts +20 -0
  86. package/dist/core/mcp-exposure.js +48 -0
  87. package/dist/core/mcp-exposure.js.map +1 -0
  88. package/dist/core/memory-rail.d.ts +37 -0
  89. package/dist/core/memory-rail.js +142 -0
  90. package/dist/core/memory-rail.js.map +1 -0
  91. package/dist/core/policy-rail.d.ts +27 -0
  92. package/dist/core/policy-rail.js +102 -0
  93. package/dist/core/policy-rail.js.map +1 -0
  94. package/dist/core/rail-utils.d.ts +10 -0
  95. package/dist/core/rail-utils.js +58 -0
  96. package/dist/core/rail-utils.js.map +1 -0
  97. package/dist/core/release-preflight.js +1 -1
  98. package/dist/core/release-preflight.js.map +1 -1
  99. package/dist/core/run-workspace.d.ts +38 -0
  100. package/dist/core/run-workspace.js +108 -0
  101. package/dist/core/run-workspace.js.map +1 -0
  102. package/dist/core/skill-routing.d.ts +2 -0
  103. package/dist/core/skill-routing.js +51 -0
  104. package/dist/core/skill-routing.js.map +1 -0
  105. package/dist/core/version.d.ts +1 -1
  106. package/dist/core/version.js +1 -1
  107. package/dist/core/workflow-store.d.ts +68 -0
  108. package/dist/core/workflow-store.js +360 -6
  109. package/dist/core/workflow-store.js.map +1 -1
  110. package/docs/agent-docs-hygiene.md +175 -0
  111. package/docs/agents.md +190 -2
  112. package/docs/benchmarking.md +213 -2
  113. package/docs/comparisons.md +195 -11
  114. package/docs/context-intelligence.md +127 -0
  115. package/docs/context-packs.md +237 -1
  116. package/docs/deep-agents-patterns.md +188 -0
  117. package/docs/diagram-rail.md +125 -0
  118. package/docs/ecosystem-influences.md +435 -0
  119. package/docs/evaluation-suite.md +196 -0
  120. package/docs/filesystem-evidence-rail.md +119 -0
  121. package/docs/future-rails-index.md +209 -0
  122. package/docs/harness-rail.md +117 -0
  123. package/docs/licensing-strategy.md +135 -0
  124. package/docs/mcp.md +96 -0
  125. package/docs/memory-rail.md +189 -0
  126. package/docs/metrics.md +136 -1
  127. package/docs/migration-v0.5.md +89 -0
  128. package/docs/policy-rail.md +184 -0
  129. package/docs/release-checklist.md +14 -0
  130. package/docs/release-workflow.md +34 -1
  131. package/docs/releases/README.md +27 -0
  132. package/docs/releases/RELEASE_NOTES_v0.2.1.md +19 -0
  133. package/docs/releases/RELEASE_NOTES_v0.2.2.md +48 -0
  134. package/docs/releases/RELEASE_NOTES_v0.2.3.md +36 -0
  135. package/docs/releases/RELEASE_NOTES_v0.3.0.md +42 -0
  136. package/docs/releases/RELEASE_NOTES_v0.3.1.md +37 -0
  137. package/docs/releases/RELEASE_NOTES_v0.3.2.md +33 -0
  138. package/docs/releases/RELEASE_NOTES_v0.3.3.md +31 -0
  139. package/docs/releases/RELEASE_NOTES_v0.4.0.md +35 -0
  140. package/docs/releases/RELEASE_NOTES_v0.4.1.md +37 -0
  141. package/docs/releases/RELEASE_NOTES_v0.5.0.md +21 -0
  142. package/docs/releases/RELEASE_NOTES_v0.5.1.md +19 -0
  143. package/docs/releases/RELEASE_NOTES_v0.5.2.md +27 -0
  144. package/docs/releases/RELEASE_NOTES_v0.6.0.md +33 -0
  145. package/docs/releases/RELEASE_NOTES_v0.6.1.md +37 -0
  146. package/docs/releases/RELEASE_NOTES_v0.7.0.md +33 -0
  147. package/docs/roadmap-agent-runtime-addendum.md +304 -0
  148. package/docs/roadmap-harness-diagram-payload-addendum.md +300 -0
  149. package/docs/rules.md +56 -0
  150. package/docs/security-model.md +56 -0
  151. package/docs/skill-rail.md +57 -0
  152. package/docs/spec-driven-workflow.md +49 -9
  153. package/docs/structured-payload-rail.md +251 -0
  154. package/docs/tutorial-antigravity.md +20 -0
  155. package/docs/tutorial-claude-code.md +23 -0
  156. package/docs/tutorial-codex.md +22 -0
  157. package/docs/tutorial-context-formats.md +28 -0
  158. package/docs/tutorial-cursor.md +23 -0
  159. package/docs/tutorial-deep-agents-role-packs.md +24 -0
  160. package/docs/tutorial-diagram-spec.md +26 -0
  161. package/docs/tutorial-gemini-cli.md +21 -0
  162. package/docs/tutorial-harness-workflow.md +25 -0
  163. package/docs/workflow-rail.md +98 -14
  164. package/examples/agents/README.md +13 -0
  165. package/package.json +2 -2
@@ -0,0 +1,68 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { estimateTokens, tokenEstimateNote } from "./token-estimator.js";
4
+ export async function compareFormats(file, root = process.cwd()) {
5
+ const absolute = path.resolve(root, file);
6
+ const raw = await fs.readFile(absolute, "utf8");
7
+ const json = tryParseJson(raw);
8
+ const lineCount = raw.split(/\r?\n/).length;
9
+ const repeatedKeys = [...raw.matchAll(/"([^"]+)"\s*:/g)].map((match) => match[1] ?? "");
10
+ const keyFrequency = new Map();
11
+ for (const key of repeatedKeys)
12
+ keyFrequency.set(key, (keyFrequency.get(key) ?? 0) + 1);
13
+ const maxKeyRepeats = Math.max(0, ...keyFrequency.values());
14
+ const warnings = [];
15
+ if (hasProbableSecret(raw))
16
+ warnings.push("probable secret-like text; redact before agent handoff");
17
+ if (json && containsHugeArray(json))
18
+ warnings.push("huge array detected; summarize or offload repeated rows");
19
+ if (raw.length > 12000)
20
+ warnings.push("long prompt context; prefer tagged blocks or offload");
21
+ return {
22
+ file,
23
+ bytes: Buffer.byteLength(raw, "utf8"),
24
+ markdownTokens: estimateTokens(raw),
25
+ jsonTokens: json ? estimateTokens(JSON.stringify(json)) : null,
26
+ taggedTokens: estimateTokens(`<soturail_context source="${file}">\n${raw}\n</soturail_context>`),
27
+ compactSuggestion: maxKeyRepeats >= 4 || lineCount > 80 ? "consider compact table/TOON-like summary for repetitive records" : "markdown is probably adequate",
28
+ taggedSuggestion: raw.length > 4000 ? "tagged blocks may help boundary clarity" : "tagged blocks optional",
29
+ warnings
30
+ };
31
+ }
32
+ export function renderFormatCompare(report) {
33
+ return [
34
+ "SotuRail format compare",
35
+ `file: ${report.file}`,
36
+ `bytes: ${report.bytes}`,
37
+ `markdown_estimated_tokens: ${report.markdownTokens}`,
38
+ `json_estimated_tokens: ${report.jsonTokens ?? "not valid json"}`,
39
+ `tagged_estimated_tokens: ${report.taggedTokens}`,
40
+ `compact_suggestion: ${report.compactSuggestion}`,
41
+ `tagged_suggestion: ${report.taggedSuggestion}`,
42
+ tokenEstimateNote(),
43
+ "",
44
+ "Warnings:",
45
+ ...(report.warnings.length > 0 ? report.warnings.map((warning) => `- ${warning}`) : ["- none"])
46
+ ].join("\n") + "\n";
47
+ }
48
+ function tryParseJson(raw) {
49
+ try {
50
+ return JSON.parse(raw);
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ function hasProbableSecret(raw) {
57
+ return /(?:api[_-]?key|token|secret|password)\s*[:=]\s*["']?[A-Za-z0-9._-]{6,}/i.test(raw)
58
+ || /authorization\s*:\s*bearer\s+[A-Za-z0-9._-]+/i.test(raw)
59
+ || /-----BEGIN [A-Z ]*PRIVATE KEY-----/.test(raw);
60
+ }
61
+ function containsHugeArray(value) {
62
+ if (Array.isArray(value))
63
+ return value.length > 50 || value.some(containsHugeArray);
64
+ if (value && typeof value === "object")
65
+ return Object.values(value).some(containsHugeArray);
66
+ return false;
67
+ }
68
+ //# sourceMappingURL=format-compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-compare.js","sourceRoot":"","sources":["../../src/core/format-compare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export interface FsSnapshot {
2
+ schemaVersion: "soturail.fs.snapshot.v1";
3
+ id: string;
4
+ createdAt: string;
5
+ files: Array<{
6
+ path: string;
7
+ size: number;
8
+ hash: string | null;
9
+ timestamp: string;
10
+ }>;
11
+ }
12
+ export declare function createFsSnapshot(root?: string): Promise<{
13
+ snapshot: FsSnapshot;
14
+ path: string;
15
+ }>;
16
+ export declare function touchedFiles(root?: string): Promise<string>;
17
+ export declare function fsDiff(root?: string): Promise<string>;
18
+ export declare function planEdit(description: string, root?: string): Promise<{
19
+ path: string;
20
+ id: string;
21
+ }>;
22
+ export declare function renderSnapshot(pathRoot: string, result: {
23
+ snapshot: FsSnapshot;
24
+ path: string;
25
+ }): string;
@@ -0,0 +1,96 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promises as fs } from "node:fs";
3
+ import path from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { ensureWorkspace, getWorkspacePaths, loadConfig, relativeToRoot, writeJson } from "./config.js";
6
+ import { scanRepository } from "./file-scanner.js";
7
+ import { hashFile } from "./git.js";
8
+ import { makeRailId } from "./rail-utils.js";
9
+ const execFileAsync = promisify(execFile);
10
+ export async function createFsSnapshot(root = process.cwd()) {
11
+ await ensureWorkspace(root);
12
+ const config = await loadConfig(root);
13
+ const repo = await scanRepository(root, config);
14
+ const files = [];
15
+ for (const file of repo.files) {
16
+ const absolute = path.join(root, file.path);
17
+ const stat = await fs.stat(absolute);
18
+ files.push({ path: file.path, size: stat.size, hash: await hashFile(absolute), timestamp: stat.mtime.toISOString() });
19
+ }
20
+ const snapshot = {
21
+ schemaVersion: "soturail.fs.snapshot.v1",
22
+ id: makeRailId("fs", root),
23
+ createdAt: new Date().toISOString(),
24
+ files
25
+ };
26
+ const filePath = path.join(getWorkspacePaths(root).fsSnapshotsDir, `${snapshot.id}.json`);
27
+ await writeJson(filePath, snapshot);
28
+ return { snapshot, path: filePath };
29
+ }
30
+ export async function touchedFiles(root = process.cwd()) {
31
+ const latest = await latestSnapshot(root);
32
+ if (!latest)
33
+ return "No filesystem snapshot found.\nCreate one with: soturail fs snapshot\n";
34
+ const current = (await createFsSnapshot(root)).snapshot;
35
+ const before = new Map(latest.files.map((file) => [file.path, file.hash]));
36
+ const changed = current.files.filter((file) => before.get(file.path) !== file.hash);
37
+ return [
38
+ "SotuRail fs touched",
39
+ `snapshot_id: ${latest.id}`,
40
+ `changed_count: ${changed.length}`,
41
+ "",
42
+ ...changed.map((file) => `- ${file.path}`)
43
+ ].join("\n") + "\n";
44
+ }
45
+ export async function fsDiff(root = process.cwd()) {
46
+ try {
47
+ const { stdout } = await execFileAsync("git", ["diff", "--stat", "--", "."], {
48
+ cwd: root,
49
+ timeout: 5000,
50
+ windowsHide: true
51
+ });
52
+ const summary = stdout.trim() || "No git diff changes detected.";
53
+ return ["SotuRail fs diff", summary].join("\n") + "\n";
54
+ }
55
+ catch {
56
+ return "SotuRail fs diff\ngit_diff: unavailable\nUse `soturail fs touched` after a snapshot for local evidence.\n";
57
+ }
58
+ }
59
+ export async function planEdit(description, root = process.cwd()) {
60
+ await ensureWorkspace(root);
61
+ const id = makeRailId("edit", description);
62
+ const filePath = path.join(getWorkspacePaths(root).fsDir, `${id}.md`);
63
+ await fs.writeFile(filePath, [
64
+ `# Planned Edit ${id}`,
65
+ "",
66
+ "schemaVersion: soturail.fs.plan-edit.v1",
67
+ `createdAt: ${new Date().toISOString()}`,
68
+ "",
69
+ "## Description",
70
+ description,
71
+ "",
72
+ "## Safety",
73
+ "- This is an intent note only.",
74
+ "- No files were modified by this command.",
75
+ ""
76
+ ].join("\n"), "utf8");
77
+ return { path: filePath, id };
78
+ }
79
+ async function latestSnapshot(root) {
80
+ const dir = getWorkspacePaths(root).fsSnapshotsDir;
81
+ const entries = await fs.readdir(dir).catch(() => []);
82
+ const json = entries.filter((entry) => entry.endsWith(".json")).sort().at(-1);
83
+ if (!json)
84
+ return null;
85
+ const raw = await fs.readFile(path.join(dir, json), "utf8");
86
+ return JSON.parse(raw);
87
+ }
88
+ export function renderSnapshot(pathRoot, result) {
89
+ return [
90
+ "SotuRail fs snapshot",
91
+ `snapshot_id: ${result.snapshot.id}`,
92
+ `files_count: ${result.snapshot.files.length}`,
93
+ `path: ${relativeToRoot(pathRoot, result.path)}`
94
+ ].join("\n") + "\n";
95
+ }
96
+ //# sourceMappingURL=fs-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-evidence.js","sourceRoot":"","sources":["../../src/core/fs-evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export interface HarnessFailureRecord {
2
+ schemaVersion: "soturail.harness.failure.v1";
3
+ id: string;
4
+ createdAt: string;
5
+ whatFailed: string;
6
+ workflowId?: string;
7
+ suspectedRootCause?: string;
8
+ preventionCandidate: string;
9
+ evidence?: string;
10
+ }
11
+ export interface HarnessContract {
12
+ schemaVersion: "soturail.harness.contract.v1";
13
+ checks: Array<{
14
+ name: string;
15
+ command: string;
16
+ required: boolean;
17
+ }>;
18
+ acceptanceRules: string[];
19
+ }
20
+ export declare function noteHarnessFailure(text: string, options?: {
21
+ workflow?: string;
22
+ cause?: string;
23
+ prevention?: string;
24
+ evidence?: string;
25
+ }, root?: string): Promise<HarnessFailureRecord>;
26
+ export declare function listHarnessFailures(root?: string): Promise<HarnessFailureRecord[]>;
27
+ export declare function explainHarnessFailure(id: string, root?: string): Promise<string>;
28
+ export declare function harnessDoctor(root?: string): Promise<string>;
29
+ export declare function initHarnessContract(root?: string): Promise<{
30
+ path: string;
31
+ created: boolean;
32
+ }>;
33
+ export declare function checkHarnessContract(root?: string): Promise<string>;
34
+ export declare function renderHarnessFailures(records: HarnessFailureRecord[]): string;
@@ -0,0 +1,158 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { appendJsonl, ensureWorkspace, getWorkspacePaths, readJsonl, relativeToRoot, writeJson } from "./config.js";
4
+ import { makeRailId } from "./rail-utils.js";
5
+ export async function noteHarnessFailure(text, options = {}, root = process.cwd()) {
6
+ await ensureWorkspace(root);
7
+ const record = {
8
+ schemaVersion: "soturail.harness.failure.v1",
9
+ id: makeRailId("hfail", text),
10
+ createdAt: new Date().toISOString(),
11
+ whatFailed: text,
12
+ preventionCandidate: options.prevention ?? "workflow check"
13
+ };
14
+ if (options.workflow)
15
+ record.workflowId = options.workflow;
16
+ if (options.cause)
17
+ record.suspectedRootCause = options.cause;
18
+ if (options.evidence)
19
+ record.evidence = options.evidence;
20
+ await appendJsonl(getWorkspacePaths(root).harnessFailuresFile, record);
21
+ return record;
22
+ }
23
+ export async function listHarnessFailures(root = process.cwd()) {
24
+ return readJsonl(getWorkspacePaths(root).harnessFailuresFile);
25
+ }
26
+ export async function explainHarnessFailure(id, root = process.cwd()) {
27
+ const record = (await listHarnessFailures(root)).find((item) => item.id === id);
28
+ if (!record)
29
+ throw new Error(`Harness failure not found: ${id}`);
30
+ return [
31
+ "SotuRail harness failure",
32
+ `id: ${record.id}`,
33
+ `created_at: ${record.createdAt}`,
34
+ `what_failed: ${record.whatFailed}`,
35
+ `workflow_id: ${record.workflowId ?? "none"}`,
36
+ `suspected_root_cause: ${record.suspectedRootCause ?? "none"}`,
37
+ `prevention_candidate: ${record.preventionCandidate}`,
38
+ `evidence: ${record.evidence ?? "none"}`
39
+ ].join("\n") + "\n";
40
+ }
41
+ export async function harnessDoctor(root = process.cwd()) {
42
+ await ensureWorkspace(root);
43
+ const paths = getWorkspacePaths(root);
44
+ const failures = await listHarnessFailures(root);
45
+ const currentWorkflow = await readCurrentWorkflow(paths.workflowCurrentFile);
46
+ const contractPath = path.join(paths.harnessContractsDir, "default.json");
47
+ const verifyPath = currentWorkflow ? path.join(paths.workflowsDir, currentWorkflow, "verify.json") : "";
48
+ const checks = [
49
+ ["README", "README.md"],
50
+ ["ROADMAP", "ROADMAP.md"],
51
+ ["tests", "tests"],
52
+ ["context_pack_support", "src/commands/context.ts"],
53
+ ["agent_docs", "docs/agents.md"],
54
+ ["policy_docs", "docs/policy-rail.md"],
55
+ ["workflow_state", ".soturail/workflows"]
56
+ ];
57
+ const lines = ["SotuRail Harness Rail doctor"];
58
+ for (const [name, file] of checks) {
59
+ lines.push(`${name}: ${(await exists(path.resolve(root, file))) ? "present" : "missing"}`);
60
+ }
61
+ lines.push(`active_workflow: ${currentWorkflow ?? "none"}`);
62
+ lines.push(`contract_present: ${await exists(contractPath)}`);
63
+ lines.push(`failure_count: ${failures.length}`);
64
+ lines.push(`latest_verify_status: ${verifyPath && await exists(verifyPath) ? "present" : "missing"}`);
65
+ lines.push(`suggested_prevention_action: ${suggestPrevention(failures)}`);
66
+ lines.push("acceptance_contract: soturail harness contract init");
67
+ lines.push("safe_default: contract check validates by default; it does not run commands unless future explicit flags add that behavior.");
68
+ lines.push("workflow_connection: workflow verify/evidence reads harness contracts and failures.");
69
+ return `${lines.join("\n")}\n`;
70
+ }
71
+ export async function initHarnessContract(root = process.cwd()) {
72
+ await ensureWorkspace(root);
73
+ const filePath = path.join(getWorkspacePaths(root).harnessContractsDir, "default.json");
74
+ if (await exists(filePath))
75
+ return { path: filePath, created: false };
76
+ await writeJson(filePath, defaultContract());
77
+ return { path: filePath, created: true };
78
+ }
79
+ export async function checkHarnessContract(root = process.cwd()) {
80
+ const filePath = path.join(getWorkspacePaths(root).harnessContractsDir, "default.json");
81
+ const raw = await fs.readFile(filePath, "utf8").catch((error) => {
82
+ if (error.code === "ENOENT")
83
+ throw new Error("Harness contract not found. Run: soturail harness contract init");
84
+ throw error;
85
+ });
86
+ const parsed = JSON.parse(raw);
87
+ const ok = parsed.schemaVersion === "soturail.harness.contract.v1"
88
+ && Array.isArray(parsed.checks)
89
+ && parsed.checks.every((check) => typeof check.name === "string" && typeof check.command === "string" && typeof check.required === "boolean")
90
+ && Array.isArray(parsed.acceptanceRules);
91
+ return [
92
+ "SotuRail harness contract check",
93
+ `path: ${relativeToRoot(root, filePath)}`,
94
+ `valid: ${ok}`,
95
+ `checks_count: ${Array.isArray(parsed.checks) ? parsed.checks.length : 0}`,
96
+ "commands_run: none",
97
+ "note: v0.5.0 validates the contract without executing checks by default."
98
+ ].join("\n") + "\n";
99
+ }
100
+ export function renderHarnessFailures(records) {
101
+ if (records.length === 0)
102
+ return "No harness failures recorded.\n";
103
+ return [
104
+ "SotuRail harness failures",
105
+ `failures_count: ${records.length}`,
106
+ "",
107
+ ...records.map((record) => `- ${record.id}: ${record.whatFailed} [candidate: ${record.preventionCandidate}]`)
108
+ ].join("\n") + "\n";
109
+ }
110
+ function defaultContract() {
111
+ return {
112
+ schemaVersion: "soturail.harness.contract.v1",
113
+ checks: [
114
+ { name: "build", command: "npm run build", required: true },
115
+ { name: "typecheck", command: "npm run typecheck", required: true },
116
+ { name: "test", command: "npm test", required: true }
117
+ ],
118
+ acceptanceRules: [
119
+ "Do not mark work as done if build fails.",
120
+ "Do not mark work as done if tests fail.",
121
+ "Do not mark work as done if policy checks fail.",
122
+ "Record evidence before release.",
123
+ "Convert repeated failures into a rule, doc, memory, workflow check or diagram/spec update."
124
+ ]
125
+ };
126
+ }
127
+ async function readCurrentWorkflow(filePath) {
128
+ const raw = await fs.readFile(filePath, "utf8").catch(() => "");
129
+ if (!raw)
130
+ return null;
131
+ try {
132
+ const parsed = JSON.parse(raw);
133
+ return parsed.id ?? null;
134
+ }
135
+ catch {
136
+ return null;
137
+ }
138
+ }
139
+ function suggestPrevention(failures) {
140
+ if (failures.length === 0)
141
+ return "record failures with soturail harness note";
142
+ const latest = failures.at(-1);
143
+ if (!latest)
144
+ return "record failures with soturail harness note";
145
+ if (/diagram|visual|spec/i.test(latest.whatFailed))
146
+ return "diagram/spec update";
147
+ return latest.preventionCandidate;
148
+ }
149
+ async function exists(filePath) {
150
+ try {
151
+ await fs.access(filePath);
152
+ return true;
153
+ }
154
+ catch {
155
+ return false;
156
+ }
157
+ }
158
+ //# sourceMappingURL=harness-rail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-rail.js","sourceRoot":"","sources":["../../src/core/harness-rail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface DuplicateKeyFinding {
2
+ key: string;
3
+ count: number;
4
+ line: number;
5
+ column: number;
6
+ }
7
+ export interface HugeArrayFinding {
8
+ path: string;
9
+ length: number;
10
+ }
11
+ export interface JsonValidationReport {
12
+ file: string;
13
+ strict: boolean;
14
+ validJson: boolean;
15
+ parseError: string | null;
16
+ duplicateKeys: DuplicateKeyFinding[];
17
+ probableSecrets: string[];
18
+ hugeArrays: HugeArrayFinding[];
19
+ result: "pass" | "warn" | "fail";
20
+ }
21
+ export declare function validateJsonFile(file: string, options?: {
22
+ strict?: boolean;
23
+ }, root?: string): Promise<JsonValidationReport>;
24
+ export declare function renderJsonValidation(report: JsonValidationReport): string;
@@ -0,0 +1,138 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ export async function validateJsonFile(file, options = {}, root = process.cwd()) {
4
+ const absolute = path.resolve(root, file);
5
+ const raw = await fs.readFile(absolute, "utf8");
6
+ const duplicateKeys = options.strict ? detectDuplicateKeys(raw) : [];
7
+ const probableSecrets = detectProbableSecrets(raw);
8
+ let parsed = null;
9
+ let parseError = null;
10
+ try {
11
+ parsed = JSON.parse(raw);
12
+ }
13
+ catch (error) {
14
+ parseError = error instanceof Error ? error.message : String(error);
15
+ }
16
+ const hugeArrays = parseError ? [] : findHugeArrays(parsed);
17
+ const validJson = parseError === null;
18
+ const warningCount = duplicateKeys.length + probableSecrets.length + hugeArrays.length;
19
+ return {
20
+ file,
21
+ strict: options.strict === true,
22
+ validJson,
23
+ parseError,
24
+ duplicateKeys,
25
+ probableSecrets,
26
+ hugeArrays,
27
+ result: !validJson ? "fail" : warningCount > 0 ? "warn" : "pass"
28
+ };
29
+ }
30
+ export function renderJsonValidation(report) {
31
+ const lines = [
32
+ "SotuRail JSON strict validate",
33
+ `file: ${report.file}`,
34
+ `strict: ${report.strict}`,
35
+ `valid_json: ${report.validJson}`,
36
+ `result: ${report.result}`
37
+ ];
38
+ if (report.parseError)
39
+ lines.push(`parse_error: ${report.parseError}`);
40
+ lines.push(`duplicate_keys: ${report.duplicateKeys.length}`, `probable_secrets: ${report.probableSecrets.length}`, `huge_arrays: ${report.hugeArrays.length}`, "", "Duplicate keys:");
41
+ lines.push(...(report.duplicateKeys.length > 0
42
+ ? report.duplicateKeys.map((finding) => `- ${finding.key} (${finding.count} copies at ${finding.line}:${finding.column})`)
43
+ : ["- none"]));
44
+ lines.push("", "Probable secrets:");
45
+ lines.push(...(report.probableSecrets.length > 0 ? report.probableSecrets.map((finding) => `- ${finding}`) : ["- none"]));
46
+ lines.push("", "Huge arrays:");
47
+ lines.push(...(report.hugeArrays.length > 0 ? report.hugeArrays.map((finding) => `- ${finding.path}: ${finding.length} items`) : ["- none"]));
48
+ lines.push("", "Safety:", "- Redact probable secrets before agent handoff.", "- Summarize or offload huge arrays instead of pasting them into prompts.");
49
+ return `${lines.join("\n")}\n`;
50
+ }
51
+ function detectDuplicateKeys(raw) {
52
+ const findings = [];
53
+ const stack = [];
54
+ for (let i = 0; i < raw.length; i += 1) {
55
+ const char = raw[i];
56
+ if (char === "{") {
57
+ stack.push({ keys: new Map() });
58
+ continue;
59
+ }
60
+ if (char === "}") {
61
+ stack.pop();
62
+ continue;
63
+ }
64
+ if (char !== "\"")
65
+ continue;
66
+ const parsed = readJsonString(raw, i);
67
+ if (!parsed)
68
+ continue;
69
+ const next = skipWhitespace(raw, parsed.end + 1);
70
+ if (raw[next] === ":" && stack.length > 0) {
71
+ const frame = stack[stack.length - 1];
72
+ const previous = frame.keys.get(parsed.value);
73
+ if (previous) {
74
+ previous.count += 1;
75
+ const position = lineColumn(raw, parsed.start);
76
+ findings.push({ key: parsed.value, count: previous.count, line: position.line, column: position.column });
77
+ }
78
+ else {
79
+ frame.keys.set(parsed.value, { count: 1, index: parsed.start });
80
+ }
81
+ }
82
+ i = parsed.end;
83
+ }
84
+ return findings;
85
+ }
86
+ function readJsonString(raw, start) {
87
+ for (let i = start + 1; i < raw.length; i += 1) {
88
+ const char = raw[i];
89
+ if (char === "\\") {
90
+ i += 1;
91
+ continue;
92
+ }
93
+ if (char === "\"") {
94
+ try {
95
+ return { value: JSON.parse(raw.slice(start, i + 1)), start, end: i };
96
+ }
97
+ catch {
98
+ return { value: raw.slice(start + 1, i), start, end: i };
99
+ }
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ function skipWhitespace(raw, index) {
105
+ let i = index;
106
+ while (i < raw.length && /\s/.test(raw[i] ?? ""))
107
+ i += 1;
108
+ return i;
109
+ }
110
+ function lineColumn(raw, index) {
111
+ const before = raw.slice(0, index);
112
+ const lines = before.split(/\r?\n/);
113
+ return { line: lines.length, column: (lines[lines.length - 1]?.length ?? 0) + 1 };
114
+ }
115
+ function detectProbableSecrets(raw) {
116
+ const findings = new Set();
117
+ const patterns = [
118
+ [/"?(api[_-]?key|token|secret|password|authorization)"?\s*:/gi, "secret-like key name"],
119
+ [/authorization\s*:\s*bearer\s+[A-Za-z0-9._-]+/gi, "authorization bearer value"],
120
+ [/-----BEGIN [A-Z ]*PRIVATE KEY-----/g, "private key block"]
121
+ ];
122
+ for (const [pattern, label] of patterns) {
123
+ if (pattern.test(raw))
124
+ findings.add(label);
125
+ }
126
+ return [...findings];
127
+ }
128
+ function findHugeArrays(value, currentPath = "$") {
129
+ if (Array.isArray(value)) {
130
+ const own = value.length > 50 ? [{ path: currentPath, length: value.length }] : [];
131
+ return [...own, ...value.flatMap((item, index) => findHugeArrays(item, `${currentPath}[${index}]`))];
132
+ }
133
+ if (value && typeof value === "object") {
134
+ return Object.entries(value).flatMap(([key, child]) => findHugeArrays(child, `${currentPath}.${key}`));
135
+ }
136
+ return [];
137
+ }
138
+ //# sourceMappingURL=json-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-validator.js","sourceRoot":"","sources":["../../src/core/json-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface McpExposureReport {
2
+ schemaVersion: "soturail.mcp.exposure.v1";
3
+ createdAt: string;
4
+ tools: Array<{
5
+ name: string;
6
+ risk: "low" | "medium" | "high";
7
+ note: string;
8
+ }>;
9
+ resources: Array<{
10
+ uri: string;
11
+ risk: "low" | "medium" | "high";
12
+ note: string;
13
+ }>;
14
+ prompts: string[];
15
+ roots: string[];
16
+ arbitraryShellExecutionExposed: boolean;
17
+ policyNotes: string[];
18
+ }
19
+ export declare function mcpExposureReport(): Promise<McpExposureReport>;
20
+ export declare function renderMcpExposure(report: McpExposureReport): string;