@overshift/sfs 1.1.0 → 1.1.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.
Files changed (43) hide show
  1. package/README.md +34 -3
  2. package/dist/cli/coverage-types.d.ts +1 -0
  3. package/dist/cli/coverage-types.d.ts.map +1 -1
  4. package/dist/cli/coverage.d.ts.map +1 -1
  5. package/dist/cli/coverage.js +14 -10
  6. package/dist/cli/coverage.js.map +1 -1
  7. package/dist/cli/help-text.d.ts +6 -0
  8. package/dist/cli/help-text.d.ts.map +1 -0
  9. package/dist/cli/help-text.js +50 -0
  10. package/dist/cli/help-text.js.map +1 -0
  11. package/dist/cli/init-templates.d.ts +1 -0
  12. package/dist/cli/init-templates.d.ts.map +1 -1
  13. package/dist/cli/init-templates.js +25 -0
  14. package/dist/cli/init-templates.js.map +1 -1
  15. package/dist/cli/init.d.ts.map +1 -1
  16. package/dist/cli/init.js +21 -16
  17. package/dist/cli/init.js.map +1 -1
  18. package/dist/cli/sfsignore.d.ts +5 -0
  19. package/dist/cli/sfsignore.d.ts.map +1 -0
  20. package/dist/cli/sfsignore.js +45 -0
  21. package/dist/cli/sfsignore.js.map +1 -0
  22. package/dist/cli/story-extractor.d.ts +3 -3
  23. package/dist/cli/story-extractor.d.ts.map +1 -1
  24. package/dist/cli/story-extractor.js +29 -16
  25. package/dist/cli/story-extractor.js.map +1 -1
  26. package/dist/cli/story-id-pattern.d.ts +10 -0
  27. package/dist/cli/story-id-pattern.d.ts.map +1 -0
  28. package/dist/cli/story-id-pattern.js +42 -0
  29. package/dist/cli/story-id-pattern.js.map +1 -0
  30. package/dist/index.js +9 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/parser/config-parser.d.ts.map +1 -1
  33. package/dist/parser/config-parser.js +3 -0
  34. package/dist/parser/config-parser.js.map +1 -1
  35. package/dist/parser/types.d.ts +1 -0
  36. package/dist/parser/types.d.ts.map +1 -1
  37. package/package.json +8 -3
  38. package/scripts/postinstall.cjs +12 -0
  39. package/skills/sfs/from-user-story-to-sfs.md +163 -0
  40. package/skills/sfs/read-sfs-session-reports.md +234 -0
  41. package/skills/sfs/run-sfs-session.md +272 -0
  42. package/skills/sfs/validate-sfs-syntax.md +291 -0
  43. package/skills/sfs/write-sfs-session-reports.md +206 -0
package/README.md CHANGED
@@ -31,6 +31,7 @@ npx sfs init
31
31
  This creates:
32
32
  - `sfs.config.md` - Base configuration
33
33
  - `example.sfs` - Example login flow
34
+ - `.sfsignore` - Coverage scan exclusions
34
35
 
35
36
  ## CLI Commands
36
37
 
@@ -55,11 +56,15 @@ npx sfs validate "stories/**/*.sfs"
55
56
  ### Coverage Report
56
57
 
57
58
  ```bash
58
- npx sfs coverage # Table format
59
- npx sfs coverage --format json # JSON output
60
- npx sfs coverage --format summary # Summary only
59
+ npx sfs coverage # Scan entire project, table output
60
+ npx sfs coverage -f json # JSON output for CI pipelines
61
+ npx sfs coverage -f summary # One-line summary
62
+ npx sfs coverage -s docs/stories # Scan only docs/stories directory
63
+ npx sfs coverage --story-pattern "JIRA-\d+" # Custom story ID pattern
61
64
  ```
62
65
 
66
+ By default, coverage scans the entire project (respecting `.sfsignore` exclusions). Use `--stories <dir>` to restrict scope.
67
+
63
68
  ## SFS File Syntax
64
69
 
65
70
  ```sfs
@@ -141,6 +146,32 @@ CLICK login button >> selector:text:Log In # Text selector
141
146
  | guest | | | Unauthenticated |
142
147
  ```
143
148
 
149
+ ### .sfsignore
150
+
151
+ Control which directories are excluded from coverage scanning:
152
+
153
+ ```
154
+ # Comments start with #
155
+ node_modules
156
+ dist
157
+ build
158
+ vendor
159
+ *.log
160
+ docs/archive
161
+ ```
162
+
163
+ Bare names auto-expand to glob patterns (e.g., `vendor` becomes `**/vendor/**`). Built-in defaults (`node_modules`, `.git`, `dist`, `build`, `coverage`) always apply.
164
+
165
+ ### Story ID Pattern
166
+
167
+ Configure custom story ID patterns in `sfs.config.md`:
168
+
169
+ ```markdown
170
+ | STORY_ID_PATTERN | JIRA-\d+ |
171
+ ```
172
+
173
+ Or via CLI: `--story-pattern "JIRA-\d+"`
174
+
144
175
  ### Environment Layering
145
176
 
146
177
  Configuration files are merged in order:
@@ -2,6 +2,7 @@ export interface CoverageOptions {
2
2
  stories?: string;
3
3
  sfs?: string;
4
4
  format?: "table" | "json" | "summary";
5
+ storyPattern?: string;
5
6
  }
6
7
  export interface UserStory {
7
8
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"coverage-types.d.ts","sourceRoot":"","sources":["../../src/cli/coverage-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"coverage-types.d.ts","sourceRoot":"","sources":["../../src/cli/coverage-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,qBAAqB,CAAC;AAU7B,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB7E"}
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,qBAAqB,CAAC;AAY7B,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC7E"}
@@ -3,8 +3,10 @@ import { glob } from "glob";
3
3
  import chalk from "chalk";
4
4
  import { extractStoryIdFromFilename, extractStoryTitle, extractStoriesFromMultiFile, deduplicateStories, extractSfsStoryId, } from "./story-extractor.js";
5
5
  import { outputResults } from "./coverage-output.js";
6
+ import { loadIgnorePatterns } from "./sfsignore.js";
7
+ import { loadStoryIdPattern } from "./story-id-pattern.js";
6
8
  export async function coverageCommand(options) {
7
- const storiesDir = options.stories ?? "stories";
9
+ const storiesDir = options.stories ?? ".";
8
10
  const sfsPattern = options.sfs ?? "**/*.sfs";
9
11
  const format = options.format ?? "table";
10
12
  // Only show header for non-JSON formats
@@ -13,7 +15,9 @@ export async function coverageCommand(options) {
13
15
  console.log();
14
16
  }
15
17
  try {
16
- const result = await calculateCoverage(storiesDir, sfsPattern);
18
+ const ignorePatterns = await loadIgnorePatterns();
19
+ const storyIdPattern = await loadStoryIdPattern(undefined, options.storyPattern);
20
+ const result = await calculateCoverage(storiesDir, sfsPattern, ignorePatterns, storyIdPattern);
17
21
  outputResults(result, format);
18
22
  }
19
23
  catch (error) {
@@ -21,36 +25,36 @@ export async function coverageCommand(options) {
21
25
  process.exit(1);
22
26
  }
23
27
  }
24
- async function calculateCoverage(storiesDir, sfsPattern) {
25
- const singleStoryFiles = await glob(`${storiesDir}/**/US-*.md`, {
26
- ignore: ["**/node_modules/**", "**/*.sfs.md"],
28
+ async function calculateCoverage(storiesDir, sfsPattern, ignorePatterns, storyIdPattern) {
29
+ const singleStoryFiles = await glob(`${storiesDir}/**/${storyIdPattern.glob}`, {
30
+ ignore: [...ignorePatterns, "**/*.sfs.md"],
27
31
  });
28
32
  const multiStoryFiles = await glob([
29
33
  `${storiesDir}/**/*user-stories*.md`,
30
34
  `${storiesDir}/**/*user.stories*.md`,
31
35
  `${storiesDir}/**/*user_stories*.md`,
32
36
  ], {
33
- ignore: ["**/node_modules/**"],
37
+ ignore: ignorePatterns,
34
38
  });
35
39
  const sfsFiles = await glob(sfsPattern, {
36
- ignore: ["**/node_modules/**"],
40
+ ignore: ignorePatterns,
37
41
  });
38
42
  const stories = [];
39
43
  for (const file of singleStoryFiles) {
40
- const id = extractStoryIdFromFilename(file);
44
+ const id = extractStoryIdFromFilename(file, storyIdPattern.regex);
41
45
  if (id) {
42
46
  const title = await extractStoryTitle(file);
43
47
  stories.push({ id, title, path: file, source: "single" });
44
48
  }
45
49
  }
46
50
  for (const file of multiStoryFiles) {
47
- const multiStories = await extractStoriesFromMultiFile(file);
51
+ const multiStories = await extractStoriesFromMultiFile(file, storyIdPattern.regex);
48
52
  stories.push(...multiStories);
49
53
  }
50
54
  const uniqueStories = deduplicateStories(stories);
51
55
  const flows = [];
52
56
  for (const file of sfsFiles) {
53
- const storyId = await extractSfsStoryId(file);
57
+ const storyId = await extractSfsStoryId(file, storyIdPattern.regex);
54
58
  if (storyId) {
55
59
  flows.push({
56
60
  storyId,
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const PROGRAM_HELP_AFTER = "\nQuick Start:\n $ npx sfs init Set up SFS in your project\n $ npx sfs run Run all SFS flow files\n $ npx sfs coverage Show user story coverage report\n\n Run \"npx sfs <command> --help\" for detailed help on each command.\n";
2
+ export declare const COVERAGE_HELP_AFTER = "\nExamples:\n $ sfs coverage Scan entire project (default)\n $ sfs coverage -f json Output as JSON\n $ sfs coverage -f summary Output compact summary\n $ sfs coverage -s stories Restrict scan to stories/ directory\n $ sfs coverage --sfs \"src/**/*.sfs\" Custom SFS file pattern\n $ sfs coverage --story-pattern \"JIRA-\\d+\" Use custom story ID pattern\n\nStory Detection:\n Single-file stories: Files matching US-*.md (or custom pattern prefix)\n Multi-file stories: Files matching *user-stories*.md, *user.stories*.md, *user_stories*.md\n Story ID formats: Headings (## US-001: Title), Bold (**US-001**), Lists (- US-001: Title), Tables (| US-001 | Title |)\n";
3
+ export declare const RUN_HELP_AFTER = "\nExamples:\n $ sfs run Run all *.sfs files\n $ sfs run stories/US-AUTH-001.sfs Run a specific file\n $ sfs run \"stories/**/*.sfs\" Run files matching a glob\n $ sfs run -e local Use local environment config\n $ sfs run -v Show verbose output\n $ sfs run --headed Run browser in headed mode\n";
4
+ export declare const INIT_HELP_AFTER = "\nExamples:\n $ sfs init Create default project files\n $ sfs init --force Overwrite existing files\n $ sfs init --skills-dir .agent/skills Custom skills directory\n\nCreated Files:\n sfs.config.md Configuration (settings, personas, hooks)\n stories/example.sfs Example flow file\n .sfsignore Coverage scan exclusions\n .gitignore Updated with SFS entries\n <skills-dir>/sfs/ SFS skill files for AI assistants\n";
5
+ export declare const VALIDATE_HELP_AFTER = "\nExamples:\n $ sfs validate stories/US-AUTH-001.sfs Validate a single file\n $ sfs validate stories/*.sfs Validate all SFS files\n";
6
+ //# sourceMappingURL=help-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-text.d.ts","sourceRoot":"","sources":["../../src/cli/help-text.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,0QAO9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,ivBAa/B,CAAC;AAEF,eAAO,MAAM,cAAc,8ZAQ1B,CAAC;AAEF,eAAO,MAAM,eAAe,8dAY3B,CAAC;AAEF,eAAO,MAAM,mBAAmB,kKAI/B,CAAC"}
@@ -0,0 +1,50 @@
1
+ export const PROGRAM_HELP_AFTER = `
2
+ Quick Start:
3
+ $ npx sfs init Set up SFS in your project
4
+ $ npx sfs run Run all SFS flow files
5
+ $ npx sfs coverage Show user story coverage report
6
+
7
+ Run "npx sfs <command> --help" for detailed help on each command.
8
+ `;
9
+ export const COVERAGE_HELP_AFTER = `
10
+ Examples:
11
+ $ sfs coverage Scan entire project (default)
12
+ $ sfs coverage -f json Output as JSON
13
+ $ sfs coverage -f summary Output compact summary
14
+ $ sfs coverage -s stories Restrict scan to stories/ directory
15
+ $ sfs coverage --sfs "src/**/*.sfs" Custom SFS file pattern
16
+ $ sfs coverage --story-pattern "JIRA-\\d+" Use custom story ID pattern
17
+
18
+ Story Detection:
19
+ Single-file stories: Files matching US-*.md (or custom pattern prefix)
20
+ Multi-file stories: Files matching *user-stories*.md, *user.stories*.md, *user_stories*.md
21
+ Story ID formats: Headings (## US-001: Title), Bold (**US-001**), Lists (- US-001: Title), Tables (| US-001 | Title |)
22
+ `;
23
+ export const RUN_HELP_AFTER = `
24
+ Examples:
25
+ $ sfs run Run all *.sfs files
26
+ $ sfs run stories/US-AUTH-001.sfs Run a specific file
27
+ $ sfs run "stories/**/*.sfs" Run files matching a glob
28
+ $ sfs run -e local Use local environment config
29
+ $ sfs run -v Show verbose output
30
+ $ sfs run --headed Run browser in headed mode
31
+ `;
32
+ export const INIT_HELP_AFTER = `
33
+ Examples:
34
+ $ sfs init Create default project files
35
+ $ sfs init --force Overwrite existing files
36
+ $ sfs init --skills-dir .agent/skills Custom skills directory
37
+
38
+ Created Files:
39
+ sfs.config.md Configuration (settings, personas, hooks)
40
+ stories/example.sfs Example flow file
41
+ .sfsignore Coverage scan exclusions
42
+ .gitignore Updated with SFS entries
43
+ <skills-dir>/sfs/ SFS skill files for AI assistants
44
+ `;
45
+ export const VALIDATE_HELP_AFTER = `
46
+ Examples:
47
+ $ sfs validate stories/US-AUTH-001.sfs Validate a single file
48
+ $ sfs validate stories/*.sfs Validate all SFS files
49
+ `;
50
+ //# sourceMappingURL=help-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-text.js","sourceRoot":"","sources":["../../src/cli/help-text.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;CAOjC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;CAalC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;CAQ7B,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;CAY9B,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;CAIlC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export declare const CONFIG_TEMPLATE = "# SFS Configuration\n\n## Settings\n\n| Setting | Value |\n|---------|-------|\n| ENTRYPOINT | http://localhost:3000 |\n| LOCALE | en-US |\n| TIMEOUT | 30000 |\n| ON FAILURE | capture screenshot |\n| PRESERVE STATE ON FAILURE | true |\n\n## Hints\n\n- Add context about your application here\n- Describe the UI layout, navigation patterns\n- Note any authentication requirements\n- Mention relevant test data or fixtures\n\n## Personas\n\n| Persona | Username | Password | Description |\n|---------|----------|----------|-------------|\n| user | testuser@example.com | {{TEST_USER_PASSWORD}} | Standard user account |\n| admin | admin@example.com | {{ADMIN_PASSWORD}} | Administrator with full access |\n| guest | | | Unauthenticated visitor |\n\n## Before Session\n\n```sfs\n# Validate environment\nASSERT file .env exists\nASSERT env-check\n\n# Start services (uncomment as needed)\n# SHELL docker compose up -d\n# WAIT FOR http://localhost:3000 to respond\n```\n\n## After Session\n\n```sfs\n# Collect logs\nSHELL mkdir -p {{RUN_DIR}}\n# SHELL docker compose logs > {{RUN_DIR}}/docker.log\n```\n\n## Before Each\n\n```sfs\n# Reset browser state\nCLEAR cookies\nCLEAR local storage\n```\n\n## After Each\n\n```sfs\n# Log completion\nSHELL echo \"$(date): Completed {{SFS_NAME}}\" >> {{RUN_DIR}}/execution.log\n```\n";
2
2
  export declare const EXAMPLE_SFS = "# example.sfs\n# Example: Basic page load verification\n\nSTORY EXAMPLE-001\nENTRYPOINT http://localhost:3000\nLOCALE en-US\n\nHINT Replace with your application context\nHINT Describe the page layout and key elements\n\nON FAILURE capture screenshot and describe visible state\n\nBEFORE THIS\n ASSERT port 3000 is open\n\n--- page-load ---\nAS user\nOBSERVE page has loaded\nOBSERVE main content is visible\n\n--- verify-elements ---\n# Add your verification steps here\nOBSERVE expected elements are present\n\nDONE WHEN page loaded successfully with expected content\n";
3
3
  export declare const GITIGNORE_ADDITIONS = "\n# SFS local config (may contain sensitive paths/settings)\nsfs.config.local.md\n\n# SFS run outputs\n/runs/\n/stories/runs/\n*.report.md\n\n# Failure screenshots\n/failures/\n";
4
+ export declare const SFSIGNORE_TEMPLATE = "# .sfsignore - Directories and files to exclude from SFS coverage scanning\n# Syntax: one pattern per line\n# Lines starting with # are comments\n# Bare directory names are auto-expanded to **/name/**\n# Patterns with * or / are used as-is\n\n# Package managers\nnode_modules\n\n# Build outputs\ndist\nbuild\ncoverage\n\n# Version control\n.git\n\n# IDE files\n.vscode\n.idea\n\n# OS files\n.DS_Store\nThumbs.db\n";
4
5
  export declare const SFS_SKILLS: string[];
5
6
  //# sourceMappingURL=init-templates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../../src/cli/init-templates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,0yCA6D3B,CAAC;AAEF,eAAO,MAAM,WAAW,4lBAyBvB,CAAC;AAEF,eAAO,MAAM,mBAAmB,sLAW/B,CAAC;AAEF,eAAO,MAAM,UAAU,UAMtB,CAAC"}
1
+ {"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../../src/cli/init-templates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,0yCA6D3B,CAAC;AAEF,eAAO,MAAM,WAAW,4lBAyBvB,CAAC;AAEF,eAAO,MAAM,mBAAmB,sLAW/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,kaAwB9B,CAAC;AAEF,eAAO,MAAM,UAAU,UAMtB,CAAC"}
@@ -98,6 +98,31 @@ sfs.config.local.md
98
98
  # Failure screenshots
99
99
  /failures/
100
100
  `;
101
+ export const SFSIGNORE_TEMPLATE = `# .sfsignore - Directories and files to exclude from SFS coverage scanning
102
+ # Syntax: one pattern per line
103
+ # Lines starting with # are comments
104
+ # Bare directory names are auto-expanded to **/name/**
105
+ # Patterns with * or / are used as-is
106
+
107
+ # Package managers
108
+ node_modules
109
+
110
+ # Build outputs
111
+ dist
112
+ build
113
+ coverage
114
+
115
+ # Version control
116
+ .git
117
+
118
+ # IDE files
119
+ .vscode
120
+ .idea
121
+
122
+ # OS files
123
+ .DS_Store
124
+ Thumbs.db
125
+ `;
101
126
  export const SFS_SKILLS = [
102
127
  "from-user-story-to-sfs.md",
103
128
  "write-sfs-session-reports.md",
@@ -1 +1 @@
1
- {"version":3,"file":"init-templates.js","sourceRoot":"","sources":["../../src/cli/init-templates.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D9B,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyB1B,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;CAWlC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,2BAA2B;IAC3B,8BAA8B;IAC9B,6BAA6B;IAC7B,wBAAwB;IACxB,oBAAoB;CACrB,CAAC"}
1
+ {"version":3,"file":"init-templates.js","sourceRoot":"","sources":["../../src/cli/init-templates.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D9B,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyB1B,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;CAWlC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBjC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,2BAA2B;IAC3B,8BAA8B;IAC9B,6BAA6B;IAC7B,wBAAwB;IACxB,oBAAoB;CACrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAkBA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqErE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAoBA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ErE"}
package/dist/cli/init.js CHANGED
@@ -1,14 +1,16 @@
1
1
  import { writeFile, readFile, access, mkdir, readdir, copyFile, } from "fs/promises";
2
2
  import { dirname, join } from "path";
3
+ import { fileURLToPath } from "url";
3
4
  import chalk from "chalk";
4
5
  import { detectMcpIntegration } from "../utils/mcp-detector.js";
5
- import { CONFIG_TEMPLATE, EXAMPLE_SFS, GITIGNORE_ADDITIONS, SFS_SKILLS, } from "./init-templates.js";
6
+ import { CONFIG_TEMPLATE, EXAMPLE_SFS, GITIGNORE_ADDITIONS, SFSIGNORE_TEMPLATE, SFS_SKILLS, } from "./init-templates.js";
6
7
  export async function initCommand(options) {
7
8
  console.log(chalk.blue("SFS - Initialize Project"));
8
9
  console.log();
9
10
  const filesToCreate = [
10
11
  { path: "sfs.config.md", content: CONFIG_TEMPLATE },
11
12
  { path: "stories/example.sfs", content: EXAMPLE_SFS },
13
+ { path: ".sfsignore", content: SFSIGNORE_TEMPLATE },
12
14
  ];
13
15
  for (const file of filesToCreate) {
14
16
  const exists = await fileExists(file.path);
@@ -57,6 +59,7 @@ export async function initCommand(options) {
57
59
  console.log(chalk.gray(" 2. Define personas with credentials for your environment"));
58
60
  console.log(chalk.gray(" 3. Create your first flow: stories/US-XXX-001.sfs"));
59
61
  console.log(chalk.gray(" 4. Run: npx sfs run"));
62
+ console.log(chalk.gray(" 5. Customize .sfsignore to exclude directories from coverage scanning"));
60
63
  }
61
64
  async function fileExists(path) {
62
65
  try {
@@ -93,51 +96,53 @@ async function detectOrCreateSkillsDir(preferred) {
93
96
  async function copySkills(destDir, force) {
94
97
  console.log();
95
98
  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
99
  const packageSkillsDir = await findPackageSkillsDir();
100
100
  if (!packageSkillsDir) {
101
101
  console.log(chalk.yellow("⚠ Could not locate SFS skills directory"));
102
102
  return;
103
103
  }
104
+ // Create sfs/ subdirectory under destination
105
+ await ensureDir(join(destDir, "sfs"));
104
106
  for (const skillFile of SFS_SKILLS) {
105
- const srcPath = join(packageSkillsDir, skillFile);
106
- const destPath = join(destDir, skillFile);
107
+ const srcPath = join(packageSkillsDir, "sfs", skillFile);
108
+ const destPath = join(destDir, "sfs", skillFile);
107
109
  try {
108
110
  const srcExists = await fileExists(srcPath);
109
111
  if (!srcExists) {
110
- console.log(chalk.yellow(`⚠ Skill not found: ${skillFile}`));
112
+ console.log(chalk.yellow(`⚠ Skill not found: sfs/${skillFile}`));
111
113
  continue;
112
114
  }
113
115
  const destExists = await fileExists(destPath);
114
116
  if (destExists && !force) {
115
- console.log(chalk.gray(`⊘ ${skillFile} already exists`));
117
+ console.log(chalk.gray(`⊘ sfs/${skillFile} already exists`));
116
118
  }
117
119
  else {
118
120
  await copyFile(srcPath, destPath);
119
- console.log(chalk.green(`✓ Copied ${skillFile}`));
121
+ console.log(chalk.green(`✓ Copied sfs/${skillFile}`));
120
122
  }
121
123
  }
122
124
  catch (err) {
123
- console.log(chalk.yellow(`⚠ Could not copy ${skillFile}: ${err instanceof Error ? err.message : "Unknown error"}`));
125
+ console.log(chalk.yellow(`⚠ Could not copy sfs/${skillFile}: ${err instanceof Error ? err.message : "Unknown error"}`));
124
126
  }
125
127
  }
126
128
  }
127
129
  async function findPackageSkillsDir() {
128
- // Try to find the skills directory relative to the current module
130
+ // Resolve package root from compiled dist/cli/init.js package root
131
+ const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
129
132
  const candidates = [
133
+ // Package-relative: works with npx, global install, local install
134
+ join(packageRoot, "skills"),
130
135
  // Development: when running from source
131
136
  join(process.cwd(), ".claude", "skills"),
132
- // Production: when installed as package (look in node_modules)
133
- join(process.cwd(), "node_modules", "@sfs", "cli", "skills"),
137
+ // Production: when installed as package in project node_modules
138
+ join(process.cwd(), "node_modules", "@overshift", "sfs", "skills"),
134
139
  join(process.cwd(), "node_modules", "sfs", "skills"),
135
140
  ];
136
141
  for (const candidate of candidates) {
137
- if (await fileExists(candidate)) {
142
+ const sfsSubdir = join(candidate, "sfs");
143
+ if (await fileExists(sfsSubdir)) {
138
144
  try {
139
- const files = await readdir(candidate);
140
- // Check if it has at least one of our skill files
145
+ const files = await readdir(sfsSubdir);
141
146
  if (files.some((f) => SFS_SKILLS.includes(f))) {
142
147
  return candidate;
143
148
  }
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function getDefaultIgnorePatterns(): string[];
2
+ export declare function parseSfsIgnore(content: string): string[];
3
+ export declare function normalizeIgnorePattern(pattern: string): string;
4
+ export declare function loadIgnorePatterns(cwd?: string): Promise<string[]>;
5
+ //# sourceMappingURL=sfsignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sfsignore.d.ts","sourceRoot":"","sources":["../../src/cli/sfsignore.ts"],"names":[],"mappings":"AAGA,wBAAgB,wBAAwB,IAAI,MAAM,EAAE,CAQnD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAa9D;AAED,wBAAsB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAYxE"}
@@ -0,0 +1,45 @@
1
+ import { readFile } from "fs/promises";
2
+ import { join } from "path";
3
+ export function getDefaultIgnorePatterns() {
4
+ return [
5
+ "**/node_modules/**",
6
+ "**/.git/**",
7
+ "**/dist/**",
8
+ "**/build/**",
9
+ "**/coverage/**",
10
+ ];
11
+ }
12
+ export function parseSfsIgnore(content) {
13
+ return content
14
+ .split("\n")
15
+ .map((line) => line.trim())
16
+ .filter((line) => line.length > 0 && !line.startsWith("#"));
17
+ }
18
+ export function normalizeIgnorePattern(pattern) {
19
+ // If it contains glob characters, use as-is
20
+ if (pattern.includes("*")) {
21
+ return pattern;
22
+ }
23
+ // Strip trailing slash for bare directory name check
24
+ const stripped = pattern.replace(/\/+$/, "");
25
+ // If the stripped form contains a path separator, it's a path — use as-is
26
+ if (stripped.includes("/")) {
27
+ return pattern;
28
+ }
29
+ // Bare directory name — wrap in glob
30
+ return `**/${stripped}/**`;
31
+ }
32
+ export async function loadIgnorePatterns(cwd) {
33
+ const defaults = getDefaultIgnorePatterns();
34
+ const dir = cwd ?? process.cwd();
35
+ const sfsignorePath = join(dir, ".sfsignore");
36
+ try {
37
+ const content = await readFile(sfsignorePath, "utf-8");
38
+ const userPatterns = parseSfsIgnore(content).map(normalizeIgnorePattern);
39
+ return [...defaults, ...userPatterns];
40
+ }
41
+ catch {
42
+ return defaults;
43
+ }
44
+ }
45
+ //# sourceMappingURL=sfsignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sfsignore.js","sourceRoot":"","sources":["../../src/cli/sfsignore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,oBAAoB;QACpB,YAAY;QACZ,YAAY;QACZ,aAAa;QACb,gBAAgB;KACjB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,OAAO;SACX,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,4CAA4C;IAC5C,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,qDAAqD;IACrD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,qCAAqC;IACrC,OAAO,MAAM,QAAQ,KAAK,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAY;IACnD,MAAM,QAAQ,GAAG,wBAAwB,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACjC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAE9C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,QAAQ,EAAE,GAAG,YAAY,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { UserStory } from "./coverage-types.js";
2
- export declare function extractStoryIdFromFilename(filePath: string): string | undefined;
2
+ export declare function extractStoryIdFromFilename(filePath: string, storyIdPattern?: RegExp): string | undefined;
3
3
  export declare function extractStoryTitle(filePath: string): Promise<string | undefined>;
4
- export declare function extractStoriesFromMultiFile(filePath: string): Promise<UserStory[]>;
4
+ export declare function extractStoriesFromMultiFile(filePath: string, storyIdPattern?: RegExp): Promise<UserStory[]>;
5
5
  export declare function deduplicateStories(stories: UserStory[]): UserStory[];
6
- export declare function extractSfsStoryId(filePath: string): Promise<string | undefined>;
6
+ export declare function extractSfsStoryId(filePath: string, storyIdPattern?: RegExp): Promise<string | undefined>;
7
7
  //# sourceMappingURL=story-extractor.d.ts.map
@@ -1 +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"}
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;AASrD,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAe7B;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,SAAS,EAAE,CAAC,CAuFtB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAcpE;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkB7B"}
@@ -1,8 +1,14 @@
1
1
  import { readFile } from "fs/promises";
2
2
  import { basename } from "path";
3
- export function extractStoryIdFromFilename(filePath) {
3
+ import { DEFAULT_STORY_ID_PATTERN } from "./story-id-pattern.js";
4
+ const DEFAULT_RE = new RegExp(DEFAULT_STORY_ID_PATTERN, "i");
5
+ function idRegex(pattern) {
6
+ return pattern ?? DEFAULT_RE;
7
+ }
8
+ export function extractStoryIdFromFilename(filePath, storyIdPattern) {
4
9
  const name = basename(filePath, ".md");
5
- const match = name.match(/^(US-[A-Z0-9-]+)/i);
10
+ const re = new RegExp(`^(${idRegex(storyIdPattern).source})`, "i");
11
+ const match = name.match(re);
6
12
  if (match?.[1]) {
7
13
  return match[1].toUpperCase();
8
14
  }
@@ -11,7 +17,7 @@ export function extractStoryIdFromFilename(filePath) {
11
17
  export async function extractStoryTitle(filePath) {
12
18
  try {
13
19
  const content = await readFile(filePath, "utf-8");
14
- const lines = content.split("\n");
20
+ const lines = content.split(/\r?\n/);
15
21
  for (const line of lines) {
16
22
  const match = line.match(/^#\s+(.+)$/);
17
23
  if (match?.[1]) {
@@ -24,16 +30,18 @@ export async function extractStoryTitle(filePath) {
24
30
  }
25
31
  return undefined;
26
32
  }
27
- export async function extractStoriesFromMultiFile(filePath) {
33
+ export async function extractStoriesFromMultiFile(filePath, storyIdPattern) {
28
34
  const stories = [];
35
+ const idSrc = idRegex(storyIdPattern).source;
29
36
  try {
30
37
  const content = await readFile(filePath, "utf-8");
31
- const lines = content.split("\n");
38
+ const lines = content.split(/\r?\n/);
32
39
  let currentStoryId;
33
40
  let currentTitle;
34
41
  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);
42
+ // Headings: ## US-XXX-001: Title
43
+ const headingRe = new RegExp(`^#{1,4}\\s+(${idSrc})[\\s:|-]+(.*)$`, "i");
44
+ const headingMatch = line.match(headingRe);
37
45
  if (headingMatch?.[1]) {
38
46
  if (currentStoryId) {
39
47
  stories.push({
@@ -47,8 +55,9 @@ export async function extractStoriesFromMultiFile(filePath) {
47
55
  currentTitle = headingMatch[2]?.trim() || undefined;
48
56
  continue;
49
57
  }
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);
58
+ // Bold: **US-XXX-001**: Description
59
+ const boldRe = new RegExp(`\\*\\*(${idSrc}):?\\*\\*[\\s:|-]*(.*)$`, "i");
60
+ const boldMatch = line.match(boldRe);
52
61
  if (boldMatch?.[1]) {
53
62
  if (currentStoryId) {
54
63
  stories.push({
@@ -62,8 +71,9 @@ export async function extractStoriesFromMultiFile(filePath) {
62
71
  currentTitle = boldMatch[2]?.trim() || undefined;
63
72
  continue;
64
73
  }
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);
74
+ // List items: - US-XXX-001: Title
75
+ const listRe = new RegExp(`^[\\s]*[-*]\\s+(${idSrc})[\\s:|-]+(.*)$`, "i");
76
+ const listMatch = line.match(listRe);
67
77
  if (listMatch?.[1]) {
68
78
  stories.push({
69
79
  id: listMatch[1].toUpperCase(),
@@ -73,8 +83,9 @@ export async function extractStoriesFromMultiFile(filePath) {
73
83
  });
74
84
  continue;
75
85
  }
76
- // Look for story IDs in table rows: | US-XXX-001 | Title | ... |
77
- const tableMatch = line.match(/\|\s*(US-[A-Z0-9-]+)\s*\|([^|]*)\|/i);
86
+ // Table rows: | US-XXX-001 | Title | ... |
87
+ const tableRe = new RegExp(`\\|\\s*(${idSrc})\\s*\\|([^|]*)\\|`, "i");
88
+ const tableMatch = line.match(tableRe);
78
89
  if (tableMatch?.[1]) {
79
90
  stories.push({
80
91
  id: tableMatch[1].toUpperCase(),
@@ -111,12 +122,14 @@ export function deduplicateStories(stories) {
111
122
  }
112
123
  return [...storyMap.values()];
113
124
  }
114
- export async function extractSfsStoryId(filePath) {
125
+ export async function extractSfsStoryId(filePath, storyIdPattern) {
126
+ const idSrc = idRegex(storyIdPattern).source;
115
127
  try {
116
128
  const content = await readFile(filePath, "utf-8");
117
- const lines = content.split("\n");
129
+ const lines = content.split(/\r?\n/);
130
+ const re = new RegExp(`^STORY\\s+(${idSrc})`, "i");
118
131
  for (const line of lines) {
119
- const match = line.match(/^STORY\s+(US-[A-Z0-9-]+)/i);
132
+ const match = line.match(re);
120
133
  if (match?.[1]) {
121
134
  return match[1].toUpperCase();
122
135
  }