@overshift/sfs 1.1.0 → 1.1.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.
- package/README.md +34 -3
- package/dist/cli/coverage-types.d.ts +1 -0
- package/dist/cli/coverage-types.d.ts.map +1 -1
- package/dist/cli/coverage.d.ts.map +1 -1
- package/dist/cli/coverage.js +14 -10
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/help-text.d.ts +6 -0
- package/dist/cli/help-text.d.ts.map +1 -0
- package/dist/cli/help-text.js +50 -0
- package/dist/cli/help-text.js.map +1 -0
- package/dist/cli/init-templates.d.ts +1 -0
- package/dist/cli/init-templates.d.ts.map +1 -1
- package/dist/cli/init-templates.js +25 -0
- package/dist/cli/init-templates.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +16 -16
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/sfsignore.d.ts +5 -0
- package/dist/cli/sfsignore.d.ts.map +1 -0
- package/dist/cli/sfsignore.js +45 -0
- package/dist/cli/sfsignore.js.map +1 -0
- package/dist/cli/story-extractor.d.ts +3 -3
- package/dist/cli/story-extractor.d.ts.map +1 -1
- package/dist/cli/story-extractor.js +26 -13
- package/dist/cli/story-extractor.js.map +1 -1
- package/dist/cli/story-id-pattern.d.ts +10 -0
- package/dist/cli/story-id-pattern.d.ts.map +1 -0
- package/dist/cli/story-id-pattern.js +42 -0
- package/dist/cli/story-id-pattern.js.map +1 -0
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/parser/config-parser.d.ts.map +1 -1
- package/dist/parser/config-parser.js +3 -0
- package/dist/parser/config-parser.js.map +1 -1
- package/dist/parser/types.d.ts +1 -0
- package/dist/parser/types.d.ts.map +1 -1
- package/package.json +8 -3
- package/scripts/postinstall.cjs +12 -0
- package/skills/sfs/from-user-story-to-sfs.md +163 -0
- package/skills/sfs/read-sfs-session-reports.md +234 -0
- package/skills/sfs/run-sfs-session.md +272 -0
- package/skills/sfs/validate-sfs-syntax.md +291 -0
- 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
|
|
59
|
-
npx sfs coverage
|
|
60
|
-
npx sfs coverage
|
|
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:
|
|
@@ -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;
|
|
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;
|
|
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"}
|
package/dist/cli/coverage.js
CHANGED
|
@@ -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 ?? "
|
|
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
|
|
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}
|
|
26
|
-
ignore: [
|
|
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:
|
|
37
|
+
ignore: ignorePatterns,
|
|
34
38
|
});
|
|
35
39
|
const sfsFiles = await glob(sfsPattern, {
|
|
36
|
-
ignore:
|
|
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,
|
package/dist/cli/coverage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,EACjB,2BAA2B,EAC3B,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
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"}
|
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAmBA,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
|
@@ -2,13 +2,14 @@ import { writeFile, readFile, access, mkdir, readdir, copyFile, } from "fs/promi
|
|
|
2
2
|
import { dirname, join } from "path";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { detectMcpIntegration } from "../utils/mcp-detector.js";
|
|
5
|
-
import { CONFIG_TEMPLATE, EXAMPLE_SFS, GITIGNORE_ADDITIONS, SFS_SKILLS, } from "./init-templates.js";
|
|
5
|
+
import { CONFIG_TEMPLATE, EXAMPLE_SFS, GITIGNORE_ADDITIONS, SFSIGNORE_TEMPLATE, SFS_SKILLS, } from "./init-templates.js";
|
|
6
6
|
export async function initCommand(options) {
|
|
7
7
|
console.log(chalk.blue("SFS - Initialize Project"));
|
|
8
8
|
console.log();
|
|
9
9
|
const filesToCreate = [
|
|
10
10
|
{ path: "sfs.config.md", content: CONFIG_TEMPLATE },
|
|
11
11
|
{ path: "stories/example.sfs", content: EXAMPLE_SFS },
|
|
12
|
+
{ path: ".sfsignore", content: SFSIGNORE_TEMPLATE },
|
|
12
13
|
];
|
|
13
14
|
for (const file of filesToCreate) {
|
|
14
15
|
const exists = await fileExists(file.path);
|
|
@@ -57,6 +58,7 @@ export async function initCommand(options) {
|
|
|
57
58
|
console.log(chalk.gray(" 2. Define personas with credentials for your environment"));
|
|
58
59
|
console.log(chalk.gray(" 3. Create your first flow: stories/US-XXX-001.sfs"));
|
|
59
60
|
console.log(chalk.gray(" 4. Run: npx sfs run"));
|
|
61
|
+
console.log(chalk.gray(" 5. Customize .sfsignore to exclude directories from coverage scanning"));
|
|
60
62
|
}
|
|
61
63
|
async function fileExists(path) {
|
|
62
64
|
try {
|
|
@@ -93,51 +95,49 @@ async function detectOrCreateSkillsDir(preferred) {
|
|
|
93
95
|
async function copySkills(destDir, force) {
|
|
94
96
|
console.log();
|
|
95
97
|
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
98
|
const packageSkillsDir = await findPackageSkillsDir();
|
|
100
99
|
if (!packageSkillsDir) {
|
|
101
100
|
console.log(chalk.yellow("⚠ Could not locate SFS skills directory"));
|
|
102
101
|
return;
|
|
103
102
|
}
|
|
103
|
+
// Create sfs/ subdirectory under destination
|
|
104
|
+
await ensureDir(join(destDir, "sfs"));
|
|
104
105
|
for (const skillFile of SFS_SKILLS) {
|
|
105
|
-
const srcPath = join(packageSkillsDir, skillFile);
|
|
106
|
-
const destPath = join(destDir, skillFile);
|
|
106
|
+
const srcPath = join(packageSkillsDir, "sfs", skillFile);
|
|
107
|
+
const destPath = join(destDir, "sfs", skillFile);
|
|
107
108
|
try {
|
|
108
109
|
const srcExists = await fileExists(srcPath);
|
|
109
110
|
if (!srcExists) {
|
|
110
|
-
console.log(chalk.yellow(`⚠ Skill not found:
|
|
111
|
+
console.log(chalk.yellow(`⚠ Skill not found: sfs/${skillFile}`));
|
|
111
112
|
continue;
|
|
112
113
|
}
|
|
113
114
|
const destExists = await fileExists(destPath);
|
|
114
115
|
if (destExists && !force) {
|
|
115
|
-
console.log(chalk.gray(`⊘
|
|
116
|
+
console.log(chalk.gray(`⊘ sfs/${skillFile} already exists`));
|
|
116
117
|
}
|
|
117
118
|
else {
|
|
118
119
|
await copyFile(srcPath, destPath);
|
|
119
|
-
console.log(chalk.green(`✓ Copied
|
|
120
|
+
console.log(chalk.green(`✓ Copied sfs/${skillFile}`));
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
catch (err) {
|
|
123
|
-
console.log(chalk.yellow(`⚠ Could not copy
|
|
124
|
+
console.log(chalk.yellow(`⚠ Could not copy sfs/${skillFile}: ${err instanceof Error ? err.message : "Unknown error"}`));
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
async function findPackageSkillsDir() {
|
|
128
|
-
// Try to find the skills directory relative to the current module
|
|
129
129
|
const candidates = [
|
|
130
130
|
// Development: when running from source
|
|
131
131
|
join(process.cwd(), ".claude", "skills"),
|
|
132
|
-
// Production: when installed as package
|
|
133
|
-
join(process.cwd(), "node_modules", "@
|
|
132
|
+
// Production: when installed as package
|
|
133
|
+
join(process.cwd(), "node_modules", "@overshift", "sfs", "skills"),
|
|
134
134
|
join(process.cwd(), "node_modules", "sfs", "skills"),
|
|
135
135
|
];
|
|
136
136
|
for (const candidate of candidates) {
|
|
137
|
-
|
|
137
|
+
const sfsSubdir = join(candidate, "sfs");
|
|
138
|
+
if (await fileExists(sfsSubdir)) {
|
|
138
139
|
try {
|
|
139
|
-
const files = await readdir(
|
|
140
|
-
// Check if it has at least one of our skill files
|
|
140
|
+
const files = await readdir(sfsSubdir);
|
|
141
141
|
if (files.some((f) => SFS_SKILLS.includes(f))) {
|
|
142
142
|
return candidate;
|
|
143
143
|
}
|
package/dist/cli/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,QAAQ,EACR,MAAM,EACN,KAAK,EACL,OAAO,EACP,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACL,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,UAAU,GACX,MAAM,qBAAqB,CAAC;AAO7B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAoB;IACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,aAAa,GAAG;QACpB,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,EAAE;QACnD,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,WAAW,EAAE;
|
|
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;
|
|
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
|
-
|
|
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
|
|
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
|
}
|
|
@@ -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
38
|
const lines = content.split("\n");
|
|
32
39
|
let currentStoryId;
|
|
33
40
|
let currentTitle;
|
|
34
41
|
for (const line of lines) {
|
|
35
|
-
//
|
|
36
|
-
const
|
|
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
|
-
//
|
|
51
|
-
const
|
|
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
|
-
//
|
|
66
|
-
const
|
|
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
|
-
//
|
|
77
|
-
const
|
|
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
129
|
const lines = content.split("\n");
|
|
130
|
+
const re = new RegExp(`^STORY\\s+(${idSrc})`, "i");
|
|
118
131
|
for (const line of lines) {
|
|
119
|
-
const match = line.match(
|
|
132
|
+
const match = line.match(re);
|
|
120
133
|
if (match?.[1]) {
|
|
121
134
|
return match[1].toUpperCase();
|
|
122
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"story-extractor.js","sourceRoot":"","sources":["../../src/cli/story-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"story-extractor.js","sourceRoot":"","sources":["../../src/cli/story-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const DEFAULT_STORY_ID_PATTERN = "US-[A-Z0-9-]+";
|
|
2
|
+
export declare const DEFAULT_STORY_ID_GLOB = "US-*.md";
|
|
3
|
+
export declare function buildStoryIdRegex(pattern: string): RegExp;
|
|
4
|
+
export declare function buildStoryFileGlob(pattern: string): string;
|
|
5
|
+
export interface StoryIdPattern {
|
|
6
|
+
regex: RegExp;
|
|
7
|
+
glob: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadStoryIdPattern(cwd?: string, cliPattern?: string): Promise<StoryIdPattern>;
|
|
10
|
+
//# sourceMappingURL=story-id-pattern.d.ts.map
|