@overshift/sfs 1.1.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 (102) hide show
  1. package/README.md +215 -0
  2. package/dist/cli/coverage-output.d.ts +3 -0
  3. package/dist/cli/coverage-output.d.ts.map +1 -0
  4. package/dist/cli/coverage-output.js +74 -0
  5. package/dist/cli/coverage-output.js.map +1 -0
  6. package/dist/cli/coverage-types.d.ts +24 -0
  7. package/dist/cli/coverage-types.d.ts.map +1 -0
  8. package/dist/cli/coverage-types.js +2 -0
  9. package/dist/cli/coverage-types.js.map +1 -0
  10. package/dist/cli/coverage.d.ts +3 -0
  11. package/dist/cli/coverage.d.ts.map +1 -0
  12. package/dist/cli/coverage.js +69 -0
  13. package/dist/cli/coverage.js.map +1 -0
  14. package/dist/cli/init-templates.d.ts +5 -0
  15. package/dist/cli/init-templates.d.ts.map +1 -0
  16. package/dist/cli/init-templates.js +108 -0
  17. package/dist/cli/init-templates.js.map +1 -0
  18. package/dist/cli/init.d.ts +7 -0
  19. package/dist/cli/init.d.ts.map +1 -0
  20. package/dist/cli/init.js +170 -0
  21. package/dist/cli/init.js.map +1 -0
  22. package/dist/cli/run.d.ts +3 -0
  23. package/dist/cli/run.d.ts.map +1 -0
  24. package/dist/cli/run.js +58 -0
  25. package/dist/cli/run.js.map +1 -0
  26. package/dist/cli/story-extractor.d.ts +7 -0
  27. package/dist/cli/story-extractor.d.ts.map +1 -0
  28. package/dist/cli/story-extractor.js +130 -0
  29. package/dist/cli/story-extractor.js.map +1 -0
  30. package/dist/cli/validate.d.ts +2 -0
  31. package/dist/cli/validate.d.ts.map +1 -0
  32. package/dist/cli/validate.js +39 -0
  33. package/dist/cli/validate.js.map +1 -0
  34. package/dist/executor/assertion-executor.d.ts +7 -0
  35. package/dist/executor/assertion-executor.d.ts.map +1 -0
  36. package/dist/executor/assertion-executor.js +206 -0
  37. package/dist/executor/assertion-executor.js.map +1 -0
  38. package/dist/executor/config-loader.d.ts +5 -0
  39. package/dist/executor/config-loader.d.ts.map +1 -0
  40. package/dist/executor/config-loader.js +48 -0
  41. package/dist/executor/config-loader.js.map +1 -0
  42. package/dist/executor/executor-types.d.ts +64 -0
  43. package/dist/executor/executor-types.d.ts.map +1 -0
  44. package/dist/executor/executor-types.js +6 -0
  45. package/dist/executor/executor-types.js.map +1 -0
  46. package/dist/executor/retry-handler.d.ts +7 -0
  47. package/dist/executor/retry-handler.d.ts.map +1 -0
  48. package/dist/executor/retry-handler.js +32 -0
  49. package/dist/executor/retry-handler.js.map +1 -0
  50. package/dist/executor/run-context.d.ts +27 -0
  51. package/dist/executor/run-context.d.ts.map +1 -0
  52. package/dist/executor/run-context.js +52 -0
  53. package/dist/executor/run-context.js.map +1 -0
  54. package/dist/executor/run-engine.d.ts +9 -0
  55. package/dist/executor/run-engine.d.ts.map +1 -0
  56. package/dist/executor/run-engine.js +140 -0
  57. package/dist/executor/run-engine.js.map +1 -0
  58. package/dist/executor/session-manager.d.ts +16 -0
  59. package/dist/executor/session-manager.d.ts.map +1 -0
  60. package/dist/executor/session-manager.js +103 -0
  61. package/dist/executor/session-manager.js.map +1 -0
  62. package/dist/executor/shell-executor.d.ts +12 -0
  63. package/dist/executor/shell-executor.d.ts.map +1 -0
  64. package/dist/executor/shell-executor.js +66 -0
  65. package/dist/executor/shell-executor.js.map +1 -0
  66. package/dist/executor/step-executor.d.ts +6 -0
  67. package/dist/executor/step-executor.d.ts.map +1 -0
  68. package/dist/executor/step-executor.js +73 -0
  69. package/dist/executor/step-executor.js.map +1 -0
  70. package/dist/index.d.ts +3 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +37 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/parser/assertion-parser.d.ts +3 -0
  75. package/dist/parser/assertion-parser.d.ts.map +1 -0
  76. package/dist/parser/assertion-parser.js +92 -0
  77. package/dist/parser/assertion-parser.js.map +1 -0
  78. package/dist/parser/command-parser.d.ts +3 -0
  79. package/dist/parser/command-parser.d.ts.map +1 -0
  80. package/dist/parser/command-parser.js +252 -0
  81. package/dist/parser/command-parser.js.map +1 -0
  82. package/dist/parser/config-parser.d.ts +16 -0
  83. package/dist/parser/config-parser.d.ts.map +1 -0
  84. package/dist/parser/config-parser.js +217 -0
  85. package/dist/parser/config-parser.js.map +1 -0
  86. package/dist/parser/sfs-parser.d.ts +3 -0
  87. package/dist/parser/sfs-parser.d.ts.map +1 -0
  88. package/dist/parser/sfs-parser.js +184 -0
  89. package/dist/parser/sfs-parser.js.map +1 -0
  90. package/dist/parser/step-parser.d.ts +3 -0
  91. package/dist/parser/step-parser.d.ts.map +1 -0
  92. package/dist/parser/step-parser.js +72 -0
  93. package/dist/parser/step-parser.js.map +1 -0
  94. package/dist/parser/types.d.ts +115 -0
  95. package/dist/parser/types.d.ts.map +1 -0
  96. package/dist/parser/types.js +3 -0
  97. package/dist/parser/types.js.map +1 -0
  98. package/dist/utils/mcp-detector.d.ts +9 -0
  99. package/dist/utils/mcp-detector.d.ts.map +1 -0
  100. package/dist/utils/mcp-detector.js +62 -0
  101. package/dist/utils/mcp-detector.js.map +1 -0
  102. package/package.json +72 -0
@@ -0,0 +1,170 @@
1
+ import { writeFile, readFile, access, mkdir, readdir, copyFile, } from "fs/promises";
2
+ import { dirname, join } from "path";
3
+ import chalk from "chalk";
4
+ import { detectMcpIntegration } from "../utils/mcp-detector.js";
5
+ import { CONFIG_TEMPLATE, EXAMPLE_SFS, GITIGNORE_ADDITIONS, SFS_SKILLS, } from "./init-templates.js";
6
+ export async function initCommand(options) {
7
+ console.log(chalk.blue("SFS - Initialize Project"));
8
+ console.log();
9
+ const filesToCreate = [
10
+ { path: "sfs.config.md", content: CONFIG_TEMPLATE },
11
+ { path: "stories/example.sfs", content: EXAMPLE_SFS },
12
+ ];
13
+ for (const file of filesToCreate) {
14
+ const exists = await fileExists(file.path);
15
+ if (exists && !options.force) {
16
+ console.log(chalk.yellow(`⊘ ${file.path} already exists (use --force to overwrite)`));
17
+ }
18
+ else {
19
+ await ensureDir(dirname(file.path));
20
+ await writeFile(file.path, file.content);
21
+ console.log(chalk.green(`✓ Created ${file.path}`));
22
+ }
23
+ }
24
+ // Update .gitignore
25
+ try {
26
+ const gitignorePath = ".gitignore";
27
+ let gitignoreContent = "";
28
+ try {
29
+ gitignoreContent = await readFile(gitignorePath, "utf-8");
30
+ }
31
+ catch {
32
+ // File doesn't exist
33
+ }
34
+ if (!gitignoreContent.includes("sfs.config.local.md")) {
35
+ await writeFile(gitignorePath, gitignoreContent + GITIGNORE_ADDITIONS);
36
+ console.log(chalk.green("✓ Updated .gitignore"));
37
+ }
38
+ else {
39
+ console.log(chalk.gray("⊘ .gitignore already contains SFS entries"));
40
+ }
41
+ }
42
+ catch {
43
+ console.log(chalk.yellow("⚠ Could not update .gitignore"));
44
+ }
45
+ // Copy skills to destination
46
+ const skillsDir = await detectOrCreateSkillsDir(options.skillsDir);
47
+ if (skillsDir) {
48
+ await copySkills(skillsDir, options.force ?? false);
49
+ }
50
+ // Check for MCP integration
51
+ await checkMcpIntegration();
52
+ console.log();
53
+ console.log(chalk.green("SFS initialized successfully!"));
54
+ console.log();
55
+ console.log("Next steps:");
56
+ console.log(chalk.gray(" 1. Edit sfs.config.md with your application settings"));
57
+ console.log(chalk.gray(" 2. Define personas with credentials for your environment"));
58
+ console.log(chalk.gray(" 3. Create your first flow: stories/US-XXX-001.sfs"));
59
+ console.log(chalk.gray(" 4. Run: npx sfs run"));
60
+ }
61
+ async function fileExists(path) {
62
+ try {
63
+ await access(path);
64
+ return true;
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ }
70
+ async function ensureDir(dir) {
71
+ if (dir && dir !== ".") {
72
+ await mkdir(dir, { recursive: true });
73
+ }
74
+ }
75
+ async function detectOrCreateSkillsDir(preferred) {
76
+ // Check preferred location first
77
+ if (preferred) {
78
+ await ensureDir(preferred);
79
+ return preferred;
80
+ }
81
+ // Check for existing skills directories
82
+ const candidates = [".claude/skills", ".agent/skills"];
83
+ for (const candidate of candidates) {
84
+ if (await fileExists(candidate)) {
85
+ return candidate;
86
+ }
87
+ }
88
+ // Default to .claude/skills
89
+ const defaultDir = ".claude/skills";
90
+ await ensureDir(defaultDir);
91
+ return defaultDir;
92
+ }
93
+ async function copySkills(destDir, force) {
94
+ console.log();
95
+ console.log(chalk.blue(`Copying SFS skills to ${destDir}...`));
96
+ // Get the SFS package skills directory
97
+ // In development: relative to this file
98
+ // In production: from the package's skills directory
99
+ const packageSkillsDir = await findPackageSkillsDir();
100
+ if (!packageSkillsDir) {
101
+ console.log(chalk.yellow("⚠ Could not locate SFS skills directory"));
102
+ return;
103
+ }
104
+ for (const skillFile of SFS_SKILLS) {
105
+ const srcPath = join(packageSkillsDir, skillFile);
106
+ const destPath = join(destDir, skillFile);
107
+ try {
108
+ const srcExists = await fileExists(srcPath);
109
+ if (!srcExists) {
110
+ console.log(chalk.yellow(`⚠ Skill not found: ${skillFile}`));
111
+ continue;
112
+ }
113
+ const destExists = await fileExists(destPath);
114
+ if (destExists && !force) {
115
+ console.log(chalk.gray(`⊘ ${skillFile} already exists`));
116
+ }
117
+ else {
118
+ await copyFile(srcPath, destPath);
119
+ console.log(chalk.green(`✓ Copied ${skillFile}`));
120
+ }
121
+ }
122
+ catch (err) {
123
+ console.log(chalk.yellow(`⚠ Could not copy ${skillFile}: ${err instanceof Error ? err.message : "Unknown error"}`));
124
+ }
125
+ }
126
+ }
127
+ async function findPackageSkillsDir() {
128
+ // Try to find the skills directory relative to the current module
129
+ const candidates = [
130
+ // Development: when running from source
131
+ join(process.cwd(), ".claude", "skills"),
132
+ // Production: when installed as package (look in node_modules)
133
+ join(process.cwd(), "node_modules", "@sfs", "cli", "skills"),
134
+ join(process.cwd(), "node_modules", "sfs", "skills"),
135
+ ];
136
+ for (const candidate of candidates) {
137
+ if (await fileExists(candidate)) {
138
+ try {
139
+ const files = await readdir(candidate);
140
+ // Check if it has at least one of our skill files
141
+ if (files.some((f) => SFS_SKILLS.includes(f))) {
142
+ return candidate;
143
+ }
144
+ }
145
+ catch {
146
+ // Continue to next candidate
147
+ }
148
+ }
149
+ }
150
+ return undefined;
151
+ }
152
+ async function checkMcpIntegration() {
153
+ const detection = await detectMcpIntegration();
154
+ console.log();
155
+ if (detection.hasPlaywright) {
156
+ console.log(chalk.green("✓ Playwright MCP server detected"));
157
+ }
158
+ else if (detection.detected) {
159
+ console.log(chalk.yellow("⚠ MCP servers found but no Playwright MCP detected"));
160
+ console.log(chalk.gray(" SFS works best with the Playwright MCP server"));
161
+ }
162
+ else {
163
+ console.log(chalk.gray("ℹ No MCP servers detected"));
164
+ console.log(chalk.gray(" Configure Playwright MCP in .claude/ for browser automation"));
165
+ }
166
+ if (detection.guidance) {
167
+ console.log(chalk.gray(` ${detection.guidance}`));
168
+ }
169
+ }
170
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RunOptions } from "../executor/run-context.js";
2
+ export declare function runCommand(files: string[], options: RunOptions): Promise<void>;
3
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CA0Df"}
@@ -0,0 +1,58 @@
1
+ import { glob } from "glob";
2
+ import chalk from "chalk";
3
+ import { createRunEngine } from "../executor/run-engine.js";
4
+ export async function runCommand(files, options) {
5
+ console.log(chalk.blue("SFS - StoryFlowSteps Runner"));
6
+ console.log();
7
+ // Find SFS files
8
+ const sfsFiles = files.length > 0
9
+ ? await resolveFiles(files)
10
+ : await glob("**/*.sfs", { ignore: ["node_modules/**"] });
11
+ if (sfsFiles.length === 0) {
12
+ console.log(chalk.yellow("No .sfs files found"));
13
+ return;
14
+ }
15
+ console.log(chalk.gray(`Found ${sfsFiles.length} SFS file(s)`));
16
+ if (options.env) {
17
+ console.log(chalk.gray(`Environment: ${options.env}`));
18
+ }
19
+ console.log();
20
+ const engine = createRunEngine();
21
+ const summary = await engine.run(sfsFiles, options);
22
+ // Display results
23
+ for (const result of summary.results) {
24
+ if (result.skipped) {
25
+ console.log(chalk.yellow(`⊘ SKIP ${result.file}${result.skipReason ? ` (${result.skipReason})` : ""}`));
26
+ }
27
+ else if (result.success) {
28
+ console.log(chalk.green(`✓ PASS ${result.file} (${result.totalDuration}ms)`));
29
+ }
30
+ else {
31
+ console.log(chalk.red(`✗ FAIL ${result.file} (${result.totalDuration}ms)`));
32
+ if (result.error) {
33
+ console.log(chalk.red(` ${result.error.message}`));
34
+ }
35
+ }
36
+ }
37
+ console.log();
38
+ console.log(chalk.gray("─".repeat(40)));
39
+ console.log(`${chalk.green(`${summary.passed} passed`)}, ${chalk.red(`${summary.failed} failed`)}, ${chalk.yellow(`${summary.skipped} skipped`)}`);
40
+ console.log(chalk.gray(`Total: ${summary.totalDuration}ms`));
41
+ if (summary.failed > 0) {
42
+ process.exitCode = 1;
43
+ }
44
+ }
45
+ async function resolveFiles(patterns) {
46
+ const files = [];
47
+ for (const pattern of patterns) {
48
+ if (pattern.includes("*")) {
49
+ const matches = await glob(pattern, { ignore: ["node_modules/**"] });
50
+ files.push(...matches);
51
+ }
52
+ else {
53
+ files.push(pattern);
54
+ }
55
+ }
56
+ return [...new Set(files)];
57
+ }
58
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { UserStory } from "./coverage-types.js";
2
+ export declare function extractStoryIdFromFilename(filePath: string): string | undefined;
3
+ export declare function extractStoryTitle(filePath: string): Promise<string | undefined>;
4
+ export declare function extractStoriesFromMultiFile(filePath: string): Promise<UserStory[]>;
5
+ export declare function deduplicateStories(stories: UserStory[]): UserStory[];
6
+ export declare function extractSfsStoryId(filePath: string): Promise<string | undefined>;
7
+ //# sourceMappingURL=story-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story-extractor.d.ts","sourceRoot":"","sources":["../../src/cli/story-extractor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,SAAS,CAOpB;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAe7B;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,SAAS,EAAE,CAAC,CAsFtB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAcpE;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAe7B"}
@@ -0,0 +1,130 @@
1
+ import { readFile } from "fs/promises";
2
+ import { basename } from "path";
3
+ export function extractStoryIdFromFilename(filePath) {
4
+ const name = basename(filePath, ".md");
5
+ const match = name.match(/^(US-[A-Z0-9-]+)/i);
6
+ if (match?.[1]) {
7
+ return match[1].toUpperCase();
8
+ }
9
+ return undefined;
10
+ }
11
+ export async function extractStoryTitle(filePath) {
12
+ try {
13
+ const content = await readFile(filePath, "utf-8");
14
+ const lines = content.split("\n");
15
+ for (const line of lines) {
16
+ const match = line.match(/^#\s+(.+)$/);
17
+ if (match?.[1]) {
18
+ return match[1].trim();
19
+ }
20
+ }
21
+ }
22
+ catch {
23
+ // Ignore read errors
24
+ }
25
+ return undefined;
26
+ }
27
+ export async function extractStoriesFromMultiFile(filePath) {
28
+ const stories = [];
29
+ try {
30
+ const content = await readFile(filePath, "utf-8");
31
+ const lines = content.split("\n");
32
+ let currentStoryId;
33
+ let currentTitle;
34
+ for (const line of lines) {
35
+ // Look for story IDs in headings: ## US-XXX-001: Title or ### US-XXX-001 - Title
36
+ const headingMatch = line.match(/^#{1,4}\s+(US-[A-Z0-9-]+)[\s:|-]+(.*)$/i);
37
+ if (headingMatch?.[1]) {
38
+ if (currentStoryId) {
39
+ stories.push({
40
+ id: currentStoryId,
41
+ title: currentTitle,
42
+ path: filePath,
43
+ source: "multi",
44
+ });
45
+ }
46
+ currentStoryId = headingMatch[1].toUpperCase();
47
+ currentTitle = headingMatch[2]?.trim() || undefined;
48
+ continue;
49
+ }
50
+ // Also look for story IDs in bold: **US-XXX-001** or **US-XXX-001:** or **US-XXX-001**:
51
+ const boldMatch = line.match(/\*\*(US-[A-Z0-9-]+):?\*\*[\s:|-]*(.*)$/i);
52
+ if (boldMatch?.[1]) {
53
+ if (currentStoryId) {
54
+ stories.push({
55
+ id: currentStoryId,
56
+ title: currentTitle,
57
+ path: filePath,
58
+ source: "multi",
59
+ });
60
+ }
61
+ currentStoryId = boldMatch[1].toUpperCase();
62
+ currentTitle = boldMatch[2]?.trim() || undefined;
63
+ continue;
64
+ }
65
+ // Look for story IDs in list items: - US-XXX-001: Title or * US-XXX-001 - Title
66
+ const listMatch = line.match(/^[\s]*[-*]\s+(US-[A-Z0-9-]+)[\s:|-]+(.*)$/i);
67
+ if (listMatch?.[1]) {
68
+ stories.push({
69
+ id: listMatch[1].toUpperCase(),
70
+ title: listMatch[2]?.trim() || undefined,
71
+ path: filePath,
72
+ source: "multi",
73
+ });
74
+ continue;
75
+ }
76
+ // Look for story IDs in table rows: | US-XXX-001 | Title | ... |
77
+ const tableMatch = line.match(/\|\s*(US-[A-Z0-9-]+)\s*\|([^|]*)\|/i);
78
+ if (tableMatch?.[1]) {
79
+ stories.push({
80
+ id: tableMatch[1].toUpperCase(),
81
+ title: tableMatch[2]?.trim() || undefined,
82
+ path: filePath,
83
+ source: "multi",
84
+ });
85
+ continue;
86
+ }
87
+ }
88
+ // Don't forget the last story
89
+ if (currentStoryId) {
90
+ stories.push({
91
+ id: currentStoryId,
92
+ title: currentTitle,
93
+ path: filePath,
94
+ source: "multi",
95
+ });
96
+ }
97
+ }
98
+ catch {
99
+ // Ignore read errors
100
+ }
101
+ return stories;
102
+ }
103
+ export function deduplicateStories(stories) {
104
+ const storyMap = new Map();
105
+ for (const story of stories) {
106
+ const existing = storyMap.get(story.id);
107
+ if (!existing ||
108
+ (existing.source === "multi" && story.source === "single")) {
109
+ storyMap.set(story.id, story);
110
+ }
111
+ }
112
+ return [...storyMap.values()];
113
+ }
114
+ export async function extractSfsStoryId(filePath) {
115
+ try {
116
+ const content = await readFile(filePath, "utf-8");
117
+ const lines = content.split("\n");
118
+ for (const line of lines) {
119
+ const match = line.match(/^STORY\s+(US-[A-Z0-9-]+)/i);
120
+ if (match?.[1]) {
121
+ return match[1].toUpperCase();
122
+ }
123
+ }
124
+ }
125
+ catch {
126
+ // Ignore read errors
127
+ }
128
+ return undefined;
129
+ }
130
+ //# sourceMappingURL=story-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story-extractor.js","sourceRoot":"","sources":["../../src/cli/story-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function validateCommand(files: string[]): Promise<void>;
2
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/cli/validate.ts"],"names":[],"mappings":"AAIA,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CpE"}
@@ -0,0 +1,39 @@
1
+ import { readFile } from "fs/promises";
2
+ import chalk from "chalk";
3
+ import { parseSfsFile } from "../parser/sfs-parser.js";
4
+ export async function validateCommand(files) {
5
+ console.log(chalk.blue("SFS - Syntax Validator"));
6
+ console.log();
7
+ let hasErrors = false;
8
+ for (const file of files) {
9
+ try {
10
+ const content = await readFile(file, "utf-8");
11
+ const result = parseSfsFile(content, file);
12
+ if (result.errors.length > 0) {
13
+ console.log(chalk.red(`✗ ${file}`));
14
+ for (const error of result.errors) {
15
+ console.log(chalk.red(` Line ${error.line}: ${error.message}`));
16
+ }
17
+ hasErrors = true;
18
+ }
19
+ else {
20
+ console.log(chalk.green(`✓ ${file}`));
21
+ if (result.warnings.length > 0) {
22
+ for (const warning of result.warnings) {
23
+ console.log(chalk.yellow(` Line ${warning.line}: ${warning.message}`));
24
+ }
25
+ }
26
+ }
27
+ }
28
+ catch (error) {
29
+ console.log(chalk.red(`✗ ${file}`));
30
+ console.log(chalk.red(` Error: ${error instanceof Error ? error.message : "Unknown error"}`));
31
+ hasErrors = true;
32
+ }
33
+ }
34
+ console.log();
35
+ if (hasErrors) {
36
+ process.exit(1);
37
+ }
38
+ }
39
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/cli/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAe;IACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAE3C,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;gBACpC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACnE,CAAC;gBACD,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;gBACtC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC/B,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBACtC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,UAAU,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAC3D,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,YAAY,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CACvE,CACF,CAAC;YACF,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SfsAssertion } from "../parser/types.js";
2
+ import type { AssertionResult, RetryConfig } from "./executor-types.js";
3
+ export interface AssertionExecutor {
4
+ execute(assertion: SfsAssertion, variables?: Record<string, string>, retryConfig?: RetryConfig): Promise<AssertionResult>;
5
+ }
6
+ export declare function createAssertionExecutor(): AssertionExecutor;
7
+ //# sourceMappingURL=assertion-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertion-executor.d.ts","sourceRoot":"","sources":["../../src/executor/assertion-executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAQxE,MAAM,WAAW,iBAAiB;IAChC,OAAO,CACL,SAAS,EAAE,YAAY,EACvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,eAAe,CAAC,CAAC;CAC7B;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAiC3D"}