@bleedingdev/modern-js-create 3.2.0-ultramodern.6 → 3.2.0-ultramodern.7

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 (23) hide show
  1. package/dist/index.js +23 -0
  2. package/package.json +1 -1
  3. package/template-workspace/.agents/rstackjs-agent-skills-LICENSE +21 -0
  4. package/template-workspace/.agents/skills/rsbuild-best-practices/SKILL.md +57 -0
  5. package/template-workspace/.agents/skills/rsdoctor-analysis/SKILL.md +96 -0
  6. package/template-workspace/.agents/skills/rsdoctor-analysis/references/command-map.md +113 -0
  7. package/template-workspace/.agents/skills/rsdoctor-analysis/references/common-analysis-patterns.md +190 -0
  8. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor-common.md +88 -0
  9. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor-rspack.md +138 -0
  10. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor-webpack.md +71 -0
  11. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor.md +39 -0
  12. package/template-workspace/.agents/skills/rsdoctor-analysis/references/rsdoctor-data-types.md +103 -0
  13. package/template-workspace/.agents/skills/rslib-best-practices/SKILL.md +58 -0
  14. package/template-workspace/.agents/skills/rslib-modern-package/SKILL.md +173 -0
  15. package/template-workspace/.agents/skills/rspack-best-practices/SKILL.md +70 -0
  16. package/template-workspace/.agents/skills/rspack-tracing/SKILL.md +75 -0
  17. package/template-workspace/.agents/skills/rspack-tracing/references/bottlenecks.md +47 -0
  18. package/template-workspace/.agents/skills/rspack-tracing/references/tracing-guide.md +38 -0
  19. package/template-workspace/.agents/skills/rspack-tracing/scripts/analyze_trace.js +184 -0
  20. package/template-workspace/.agents/skills/rstest-best-practices/SKILL.md +133 -0
  21. package/template-workspace/.agents/skills-lock.json +56 -0
  22. package/template-workspace/AGENTS.md +28 -0
  23. package/template-workspace/scripts/validate-ultramodern-workspace.mjs.handlebars +67 -0
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: rspack-tracing
3
+ description: Comprehensive guide and toolkit for diagnosing Rspack build issues. Quickly identify where crashes/errors occur, or perform detailed performance profiling to resolve bottlenecks. Use when the user encounters build failures, slow builds, or wants to optimize Rspack performance.
4
+ ---
5
+
6
+ # Rspack Tracing & Performance Profiling
7
+
8
+ ## When to Use This Skill
9
+
10
+ Use this skill when you need to:
11
+
12
+ 1. Diagnose why an Rspack build is slow.
13
+ 2. Understand which plugins or loaders are taking the most time.
14
+ 3. Analyze a user-provided Rspack trace file.
15
+ 4. Guide a user to capture a performance profile.
16
+
17
+ ## Workflow
18
+
19
+ ### 1. Capture a Trace
20
+
21
+ First, ask the user to run their build with tracing enabled.
22
+
23
+ ```bash
24
+ # Set environment variables for logging to a file
25
+ RSPACK_PROFILE=TRACE RSPACK_TRACE_LAYER=logger RSPACK_TRACE_OUTPUT=./trace.json pnpm build
26
+ ```
27
+
28
+ This will generate a trace file in a timestamped directory like `.rspack-profile-{timestamp}-{pid}/trace.json`.
29
+
30
+ See [references/tracing-guide.md](references/tracing-guide.md) for more details on configuration.
31
+
32
+ ### 2. Quick Diagnosis for Crashes/Errors
33
+
34
+ If the user wants to identify **which stage a crash or error occurred in**, use `tail` to quickly view the last events without running the full analysis:
35
+
36
+ ```bash
37
+ # Navigate to the generated profile directory
38
+ cd .rspack-profile-*/
39
+
40
+ # View the last 20 events to see where the build failed
41
+ tail -n 20 trace.json
42
+ ```
43
+
44
+ The last events will show the span names and targets where the build stopped, helping to quickly pinpoint the problematic stage, plugin, or loader.
45
+
46
+ ### 3. Full Performance Analysis
47
+
48
+ For detailed performance profiling (not just crash diagnosis), ask the user to run the bundled analysis script on the generated trace file.
49
+
50
+ ```bash
51
+ # Navigate to the generated profile directory
52
+ cd .rspack-profile-*/
53
+
54
+ # Run the analysis script
55
+ node ${CLAUDE_PLUGIN_ROOT}/skills/tracing/scripts/analyze_trace.js trace.json
56
+ ```
57
+
58
+ ### 4. Interpret Results
59
+
60
+ Use the output from the script to identify bottlenecks.
61
+ Consult [references/bottlenecks.md](references/bottlenecks.md) to map span names to actionable fixes.
62
+
63
+ ### 5. Locate Slow Plugins
64
+
65
+ Based on the "Top Slowest Hooks" from the analysis script:
66
+
67
+ 1. **Identify the Hook**: Note the hook name (e.g., `hook:CompilationOptimizeChunks`).
68
+ 2. **Inspect Configuration**: Read `rspack.config.js` or `rsbuild.config.ts`.
69
+ 3. **Map Hook to Plugin**: Look for plugins and their sources that tap into that specific hook.
70
+ 4. **Output**: Output the paths, lines and columns of the suspected plugin source code.
71
+
72
+ ## Common Scenarios & Quick Fixes
73
+
74
+ - [Bottleneck Reference](references/bottlenecks.md): Mapping spans to concepts.
75
+ - [Tracing Guide](references/tracing-guide.md): Detailed usage of `RSPACK_PROFILE`.
@@ -0,0 +1,47 @@
1
+ # Understanding Rspack Performance Bottlenecks
2
+
3
+ This reference maps internal Rspack tracing spans to high-level concepts to help you identify performance issues.
4
+
5
+ ## Core Compilation Phases
6
+
7
+ | Span Name | Description | Potential Bottlenecks |
8
+ | :---------------------- | :------------------------------------------------------------- | :-------------------------------------------------------------------------------- |
9
+ | `tracing::profiling` | The entire build process. | Overall slowness. |
10
+ | `compiler::make` | **Make Phase**: Resolving, loading, and parsing modules. | Heavy loaders (babel/swc with complex configs), too many files, slow file system. |
11
+ | `compiler::seal` | **Seal Phase**: Optimizing, splitting chunks, generating code. | Complex code splitting, heavy minification, many modules. |
12
+ | `compiler::emit_assets` | **Emit Phase**: Writing files to disk. | Slow disk I/O, huge output files. |
13
+
14
+ ## Detailed Spans
15
+
16
+ ### Make Phase (Module Processing)
17
+
18
+ - `resolver::resolve`: Resolving import paths.
19
+ - **High Time?**: Check for complex `resolve.alias` or `resolve.modules`, or too many standard fallbacks.
20
+ - `loader::run_loaders`: Executing loaders (JavaScript/Rust).
21
+ - **High Time?**: Identify which loader is slow. If `sass-loader` or `babel-loader` is slow, consider caching (`cache: true` in config) or using `swc-loader`.
22
+ - `parser::parse`: Parsing source code into AST.
23
+ - **High Time?**: Large files?
24
+
25
+ ### Seal Phase (Optimization)
26
+
27
+ - `compilation::code_generation`: Generating final code from AST.
28
+ - `compilation::optimize_chunks`: Splitting chunks (SplitChunksPlugin).
29
+ - `k_means_splitter`: If you see this, complex splitting logic is running.
30
+ - `js_minimizer`: Minification (SwcJsMinimizer).
31
+ - **High Time?**: Disable minimization in dev (`optimization.minimize: false`) for speed.
32
+
33
+ ### General
34
+
35
+ - `read_file`: Reading files from disk.
36
+ - `write_file`: Writing artifacts to disk.
37
+
38
+ ## Common Fixes
39
+
40
+ 1. **Slow `make` phase**:
41
+ - Use `experiments.cache` (Persistent Cache).
42
+ - Exclude `node_modules` from expensive loaders.
43
+ - Switch to lighter loaders (e.g. `swc-loader` vs `babel-loader`).
44
+ 2. **Slow `seal` phase**:
45
+ - Reduce `splitChunks` complexity.
46
+ - Disable `sourcemap` in production if acceptable cost.
47
+ - Upgrade to latest Rspack (performance improvements are frequent).
@@ -0,0 +1,38 @@
1
+ # Rspack Tracing Guide
2
+
3
+ Tracing allows you to visualize exactly what Rspack is doing during a build.
4
+
5
+ ## Enabling Tracing
6
+
7
+ Rspack uses several environment variables to control tracing.
8
+
9
+ **Command:**
10
+
11
+ ```bash
12
+ RSPACK_PROFILE=TRACE RSPACK_TRACE_LAYER=logger RSPACK_TRACE_OUTPUT=./trace.json rspack build
13
+ ```
14
+
15
+ ### Variables
16
+
17
+ **`RSPACK_PROFILE`**: Controls the granularity of the trace.
18
+
19
+ - `TRACE`: Captures all spans. (Recommended for deep analysis)
20
+ - `DEBUG`, `INFO`, `WARN`, `ERROR`, `CRITICAL`
21
+ - `OFF`: Disables tracing.
22
+
23
+ **`RSPACK_TRACE_LAYER`**: Controls the output format.
24
+
25
+ - `logger`: Outputs standard JSON logging (required for the analysis script).
26
+
27
+ ## Output
28
+
29
+ After running the command, Rspack will generate the file specified in `RSPACK_TRACE_OUTPUT`.
30
+
31
+ ## Using the Skill's Analysis Tool
32
+
33
+ This skill includes a script to summarize the trace file.
34
+
35
+ ```bash
36
+ # Run the included script
37
+ node scripts/analyze_trace.js <path-to-trace-file>
38
+ ```
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ // Parse duration string (e.g., "1.23ms", "456.78µs", "0.12s") to milliseconds
7
+ function parseDuration(durationStr) {
8
+ if (!durationStr) return 0;
9
+
10
+ const match = durationStr.match(/^([\d.]+)(ms|µs|s|ns)$/);
11
+ if (!match) return 0;
12
+
13
+ const value = parseFloat(match[1]);
14
+ const unit = match[2];
15
+
16
+ switch (unit) {
17
+ case 's':
18
+ return value * 1000;
19
+ case 'ms':
20
+ return value;
21
+ case 'µs':
22
+ return value / 1000;
23
+ case 'ns':
24
+ return value / 1000000;
25
+ default:
26
+ return value;
27
+ }
28
+ }
29
+
30
+ // Get trace file path
31
+ const tracePath = process.argv[2] || path.join(__dirname, 'trace.json');
32
+
33
+ if (!fs.existsSync(tracePath)) {
34
+ console.error(`Error: Trace file not found at ${tracePath}`);
35
+ console.error('Usage: node analyze_trace.js <path-to-trace.json>');
36
+ process.exit(1);
37
+ }
38
+
39
+ console.log(`Analyzing trace file: ${tracePath}\n`);
40
+
41
+ try {
42
+ const fileContent = fs.readFileSync(tracePath, 'utf8');
43
+
44
+ // Parse line-delimited JSON
45
+ const events = fileContent
46
+ .trim()
47
+ .split('\n')
48
+ .map(line => {
49
+ try {
50
+ return JSON.parse(line);
51
+ } catch (err) {
52
+ return null;
53
+ }
54
+ })
55
+ .filter(Boolean);
56
+
57
+ if (!events.length) {
58
+ console.error('No valid trace events found.');
59
+ process.exit(1);
60
+ }
61
+
62
+ console.log('=== Rspack Build Performance Analysis ===\n');
63
+ console.log(`Total events: ${events.length}\n`);
64
+
65
+ // Categorize events by target
66
+ const pluginStats = new Map();
67
+ const loaderStats = new Map();
68
+
69
+ events.forEach(event => {
70
+ const target = event.target;
71
+ const timeField = event.fields?.['time.busy'];
72
+
73
+ if (!timeField) return;
74
+
75
+ const duration = parseDuration(timeField);
76
+
77
+ if (target === 'Plugin Analysis') {
78
+ // Plugin performance
79
+ const pluginName = event.span?.name;
80
+ if (!pluginName) return;
81
+
82
+ if (!pluginStats.has(pluginName)) {
83
+ pluginStats.set(pluginName, {
84
+ count: 0,
85
+ total: 0,
86
+ max: 0,
87
+ min: Infinity,
88
+ });
89
+ }
90
+
91
+ const stat = pluginStats.get(pluginName);
92
+ stat.count++;
93
+ stat.total += duration;
94
+ stat.max = Math.max(stat.max, duration);
95
+ stat.min = Math.min(stat.min, duration);
96
+ } else if (target === 'Loader Analysis') {
97
+ // Loader performance
98
+ let loaderName = event.span?.name;
99
+
100
+ // For pitch phase (span.name is null), use resource path
101
+ if (!loaderName) {
102
+ const resource = event.fields?.resource;
103
+ if (resource) {
104
+ // Extract filename from resource path
105
+ const cleanResource = resource.replace(/^"|"$/g, ''); // Remove quotes
106
+ const filename = cleanResource.split('/').pop();
107
+ loaderName = `Loader pitch for ${filename}`;
108
+ } else {
109
+ loaderName = 'Loader pitch (unknown resource)';
110
+ }
111
+ }
112
+
113
+ if (!loaderStats.has(loaderName)) {
114
+ loaderStats.set(loaderName, {
115
+ count: 0,
116
+ total: 0,
117
+ max: 0,
118
+ min: Infinity,
119
+ });
120
+ }
121
+
122
+ const stat = loaderStats.get(loaderName);
123
+ stat.count++;
124
+ stat.total += duration;
125
+ stat.max = Math.max(stat.max, duration);
126
+ stat.min = Math.min(stat.min, duration);
127
+ }
128
+ });
129
+
130
+ // Display Plugin Analysis
131
+ if (pluginStats.size > 0) {
132
+ console.log('🔌 Plugin Analysis (by name):');
133
+ console.log('─'.repeat(80));
134
+
135
+ const sortedPlugins = [...pluginStats.entries()].sort(
136
+ (a, b) => b[1].total - a[1].total,
137
+ );
138
+
139
+ sortedPlugins.forEach(([name, stat]) => {
140
+ const avg = stat.total / stat.count;
141
+ console.log(`${name}`);
142
+ console.log(
143
+ ` Total: ${stat.total.toFixed(2)}ms | Count: ${stat.count} | ` +
144
+ `Avg: ${avg.toFixed(2)}ms | Max: ${stat.max.toFixed(2)}ms | Min: ${stat.min.toFixed(2)}ms`,
145
+ );
146
+ console.log('');
147
+ });
148
+
149
+ const totalPluginTime = [...pluginStats.values()].reduce(
150
+ (sum, stat) => sum + stat.total,
151
+ 0,
152
+ );
153
+ console.log(`Total Plugin Time: ${totalPluginTime.toFixed(2)}ms\n`);
154
+ }
155
+
156
+ // Display Loader Analysis
157
+ if (loaderStats.size > 0) {
158
+ console.log('\n🔧 Loader Analysis (by name):');
159
+ console.log('─'.repeat(80));
160
+
161
+ const sortedLoaders = [...loaderStats.entries()].sort(
162
+ (a, b) => b[1].total - a[1].total,
163
+ );
164
+
165
+ sortedLoaders.forEach(([name, stat]) => {
166
+ const avg = stat.total / stat.count;
167
+ console.log(`${name}`);
168
+ console.log(
169
+ ` Total: ${stat.total.toFixed(2)}ms | Count: ${stat.count} | ` +
170
+ `Avg: ${avg.toFixed(2)}ms | Max: ${stat.max.toFixed(2)}ms | Min: ${stat.min.toFixed(2)}ms`,
171
+ );
172
+ console.log('');
173
+ });
174
+
175
+ const totalLoaderTime = [...loaderStats.values()].reduce(
176
+ (sum, stat) => sum + stat.total,
177
+ 0,
178
+ );
179
+ console.log(`Total Loader Time: ${totalLoaderTime.toFixed(2)}ms\n`);
180
+ }
181
+ } catch (err) {
182
+ console.error('Error processing trace file:', err);
183
+ process.exit(1);
184
+ }
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: rstest-best-practices
3
+ description: Rstest best practices for config, CLI workflow, test writing, mocking, snapshot testing, DOM testing, coverage, multi-project setup, CI integration, performance and debugging. Use when writing, reviewing, or troubleshooting Rstest test projects.
4
+ ---
5
+
6
+ # Rstest Best Practices
7
+
8
+ Apply these rules when writing or reviewing Rstest test projects.
9
+
10
+ ## Configuration
11
+
12
+ - Use `rstest.config.ts` and `defineConfig` from `@rstest/core`
13
+ - Prefer explicit imports `import { test, expect, describe } from '@rstest/core'` over `globals: true`
14
+ - For Rsbuild projects, use `@rstest/adapter-rsbuild` with `extends: withRsbuildConfig()` to reuse build config
15
+ - For Rslib projects, use `@rstest/adapter-rslib` with `extends: withRslibConfig()` to reuse build config
16
+ - Use `setupFiles` for shared test setup (e.g., custom matchers, cleanup hooks)
17
+ - When using Rsbuild plugins (e.g., `@rsbuild/plugin-react`), add them via the `plugins` field
18
+ - For deep-level or advanced build configuration needs, use `tools.rspack` or `tools.bundlerChain`
19
+
20
+ ## CLI
21
+
22
+ - Use `rstest` or `rstest run` to run tests (`run` disables watch mode, suitable for CI)
23
+ - Use `rstest --watch` or `rstest watch` for local development with file watching
24
+ - Use `rstest list` to list all test files and test names
25
+ - Use `rstest -u` to update snapshots
26
+ - Use `--reporter=verbose` when debugging test failures for detailed output
27
+ - Use `--config` (`-c`) to specify a custom config file path
28
+
29
+ ## Test writing
30
+
31
+ - Import test APIs from `@rstest/core`: `test`, `describe`, `expect`, `beforeEach`, `afterEach`, etc.
32
+ - Use `test` or `it` for test cases; use `describe` for grouping related tests
33
+ - Use `.only` to focus on specific tests during development, but never commit `.only` to the codebase
34
+ - Use `.skip` or `.todo` to mark incomplete or temporarily skipped tests
35
+ - Prefer small, focused test cases that test a single behavior
36
+ - For async error paths, prefer `await expect(fn()).rejects.toThrow(ErrorClass)` (or `.rejects.toMatchObject({ ... })`) over `try/catch` with `expect.fail` or `.catch(e => e)` patterns — the matcher form fails clearly if the promise unexpectedly resolves, keeps the assertion in one chain, and avoids forgetting to assert the throw at all
37
+ - For async happy paths, use `await expect(fn()).resolves.toEqual(...)` for the same reason
38
+ - Use `includeSource` for in-source testing of small utility functions (Rust-style `import.meta.rstest`)
39
+ - For in-source tests, wrap test code in `if (import.meta.rstest) { ... }` and define `import.meta.rstest` as `false` in production build config
40
+
41
+ ## Test environment
42
+
43
+ - Use `testEnvironment: 'node'` (default) for Node.js / server-side code
44
+ - Use `testEnvironment: 'jsdom'` or `testEnvironment: 'happy-dom'` for DOM / browser API testing
45
+ - Install `jsdom` or `happy-dom` as a dev dependency when using DOM environments
46
+ - Prefer `happy-dom` for faster DOM testing; use `jsdom` when better browser API compatibility is needed
47
+ - For real browser testing, use `@rstest/browser` with Playwright
48
+ - Use inline project configs to run different test environments within one project (e.g., `node` and `jsdom` projects)
49
+
50
+ ## React / Vue testing
51
+
52
+ - For React: use `@rsbuild/plugin-react` plugin and `@testing-library/react` for component testing
53
+ - For Vue: use `@rsbuild/plugin-vue` plugin and `@testing-library/vue` for component testing
54
+ - Create a `rstest.setup.ts` with `expect.extend(jestDomMatchers)` and `afterEach(() => cleanup())` for Testing Library
55
+ - Add the setup file to `setupFiles` in config
56
+ - For SSR testing, use `testEnvironment: 'node'` and test with `react-dom/server` or framework-specific SSR APIs
57
+
58
+ ## Mocking
59
+
60
+ - Use `rs.mock('./module')` to mock modules
61
+ - Use `rs.fn()` to create mock functions
62
+ - Use `rs.spyOn(object, 'method')` to spy on methods
63
+ - Prefer `clearMocks`, `resetMocks`, or `restoreMocks` config options to automatically clean up mocks between tests
64
+ - Use factory functions in `rs.mock('./module', () => ({ ... }))` to provide mock implementations
65
+
66
+ ## Snapshot testing
67
+
68
+ - Use `toMatchSnapshot()` for general snapshot testing
69
+ - Use `toMatchInlineSnapshot()` for small, readable inline snapshots
70
+ - Use `toMatchFileSnapshot()` for large or structured outputs (e.g., HTML, generated code)
71
+ - Keep snapshots concise — only include relevant data, avoid timestamps and session IDs
72
+ - Use `expect.addSnapshotSerializer()` to mask paths or sensitive data in snapshots
73
+ - Use `path-serializer` to normalize file paths across platforms
74
+ - Review snapshot changes carefully in code review
75
+
76
+ ## Coverage
77
+
78
+ - Enable coverage with `--coverage` CLI flag or `coverage.enabled: true` in config
79
+ - Install `@rstest/coverage-istanbul` for the Istanbul coverage provider
80
+ - Use `coverage.include` to specify source files for coverage (e.g., `['src/**/*.{js,ts,tsx}']`)
81
+ - Use `coverage.thresholds` to enforce minimum coverage requirements
82
+ - Use `coverage.reporters` to generate reports in different formats (e.g., `text`, `lcov`, `html`)
83
+
84
+ ## Multi-project testing
85
+
86
+ - Use `projects` field in root config to define multiple test projects
87
+ - For monorepos, use glob patterns like `'packages/*'` to auto-discover sub-projects
88
+ - Use `defineProject` helper in sub-project configs
89
+ - Extract shared config and use `mergeRstestConfig` to compose project configs
90
+ - Global options (`reporters`, `pool`, `isolate`, `coverage`, `bail`) must be set at the root level, not in projects
91
+
92
+ ## CI integration
93
+
94
+ - Use `rstest run` (not `rstest watch`) in CI
95
+ - Use `--shard` for parallel test execution across CI machines (e.g., `--shard 1/3`)
96
+ - Use `--reporter=blob` with `rstest merge-reports` to combine sharded results
97
+ - Use `--reporter=junit` with `outputPath` for CI report integration
98
+ - The `github-actions` reporter is auto-enabled in GitHub Actions for inline error annotations
99
+ - Use `--bail` to stop early on first failure when appropriate
100
+
101
+ ## Performance
102
+
103
+ - Disable `isolate` (`--no-isolate`) when tests have no side effects for faster execution via module cache reuse
104
+ - Use `pool.maxWorkers` to control parallelism based on available resources
105
+ - Keep test build fast by avoiding unnecessary Rspack plugins in test config
106
+ - Use test filtering (`rstest <pattern>` or `-t <name>`) to run only relevant tests during development
107
+ - Leverage watch mode's incremental re-runs for fast local feedback
108
+
109
+ ## Debugging
110
+
111
+ - Run with `DEBUG=rstest` to enable debug mode, which writes final configs and build outputs to disk
112
+ - Read generated files in `dist/.rstest-temp/.rsbuild/` to confirm final Rstest/Rsbuild/Rspack config
113
+ - Use VS Code's JavaScript Debug Terminal to run `rstest` with breakpoints
114
+ - Use `--reporter=verbose` for detailed per-test output
115
+ - Use `--printConsoleTrace` to trace console calls to their source
116
+ - Add VS Code launch config for debugging specific test files with `@rstest/core/bin/rstest.js`
117
+
118
+ ## Profiling
119
+
120
+ - Use Rsdoctor with `RSDOCTOR=true rstest run` to analyze test build performance
121
+ - Use `samply` for native profiling of both main and worker processes
122
+ - Use Node.js `--heap-prof` for memory profiling
123
+
124
+ ## Toolchain integration
125
+
126
+ - Use the official VS Code extension (`rstack.rstest`) for in-editor test running and debugging
127
+ - For Rslib libraries, use `@rstest/adapter-rslib` for config reuse
128
+ - For Rsbuild apps, use `@rstest/adapter-rsbuild` for config reuse
129
+ - Use `process.env.RSTEST` to detect test environment and apply test-specific config
130
+
131
+ ## Documentation
132
+
133
+ - For the latest Rstest docs, read https://rstest.rs/llms.txt
@@ -0,0 +1,56 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "source": {
4
+ "repository": "https://github.com/rstackjs/agent-skills",
5
+ "commit": "61c948b42512e223bad44b83af4080eba48b2677",
6
+ "license": "MIT",
7
+ "licensePath": ".agents/rstackjs-agent-skills-LICENSE"
8
+ },
9
+ "installDir": ".agents/skills",
10
+ "baseline": [
11
+ {
12
+ "name": "rsbuild-best-practices",
13
+ "path": ".agents/skills/rsbuild-best-practices",
14
+ "reason": "Modern.js application build configuration and Rsbuild troubleshooting"
15
+ },
16
+ {
17
+ "name": "rspack-best-practices",
18
+ "path": ".agents/skills/rspack-best-practices",
19
+ "reason": "Rspack bundling, CSS, asset, profiling, and production behavior"
20
+ },
21
+ {
22
+ "name": "rspack-tracing",
23
+ "path": ".agents/skills/rspack-tracing",
24
+ "reason": "Trace-backed Rspack failure and performance debugging"
25
+ },
26
+ {
27
+ "name": "rsdoctor-analysis",
28
+ "path": ".agents/skills/rsdoctor-analysis",
29
+ "reason": "Evidence-backed bundle composition, duplication, and retained-module analysis"
30
+ },
31
+ {
32
+ "name": "rslib-best-practices",
33
+ "path": ".agents/skills/rslib-best-practices",
34
+ "reason": "Rslib shared package and design-system library authoring"
35
+ },
36
+ {
37
+ "name": "rslib-modern-package",
38
+ "path": ".agents/skills/rslib-modern-package",
39
+ "reason": "Modern package contracts, exports, declarations, side effects, and release readiness"
40
+ },
41
+ {
42
+ "name": "rstest-best-practices",
43
+ "path": ".agents/skills/rstest-best-practices",
44
+ "reason": "Rstest configuration, test writing, mocking, snapshots, coverage, and CI behavior"
45
+ }
46
+ ],
47
+ "excludedByDefault": [
48
+ "migrate-to-rsbuild",
49
+ "migrate-to-rslib",
50
+ "migrate-to-rslint",
51
+ "migrate-to-rstest",
52
+ "rsbuild-v2-upgrade",
53
+ "rspack-v2-upgrade",
54
+ "rspress-v2-upgrade"
55
+ ]
56
+ }
@@ -0,0 +1,28 @@
1
+ # UltraModern Agent Contract
2
+
3
+ This workspace is generated as an agent-ready UltraModern.js SuperApp. Agents should treat the files under `.agents/skills` as local project instructions, not optional reading.
4
+
5
+ ## Required Skill Baseline
6
+
7
+ Use these skills when the task touches the matching subsystem:
8
+
9
+ - `rsbuild-best-practices`: Modern.js app build configuration, Rsbuild options, assets, type checking, and build debugging.
10
+ - `rspack-best-practices`: Rspack-level bundling, CSS, assets, profiling, and production build behavior.
11
+ - `rspack-tracing`: Rspack build failures, slow builds, crash localization, and trace analysis.
12
+ - `rsdoctor-analysis`: Evidence-based bundle analysis from `rsdoctor-data.json`, including duplicate packages, large chunks, and retained modules.
13
+ - `rslib-best-practices`: Shared packages, generated libraries, declaration output, and Rslib configuration.
14
+ - `rslib-modern-package`: Package contracts for shared libraries, exports, side effects, dependency placement, README, and release readiness.
15
+ - `rstest-best-practices`: Rstest configuration, test writing, mocking, snapshots, coverage, and CI test behavior.
16
+
17
+ ## Project Priorities
18
+
19
+ - Keep `presetUltramodern` as the single preset.
20
+ - Prefer Effect for BFF/service code.
21
+ - Prefer TanStack Router for app routing.
22
+ - Keep design-system code as a normal Micro Frontend or shared package, not a special core path.
23
+ - Keep generated packages explicit and publishable: stable `exports`, correct declarations, small public APIs, and clear ownership metadata.
24
+ - Do not add migration tooling or codemods unless the project owner explicitly asks for migration work.
25
+
26
+ ## Skill Provenance
27
+
28
+ The vendored Rstack skills are pinned in `.agents/skills-lock.json`. Do not update, remove, or replace them casually. If a skill needs updating, update the lock file and run `pnpm ultramodern:check`.
@@ -4,12 +4,23 @@ import path from 'node:path';
4
4
  const root = process.cwd();
5
5
  const packageScope = '{{packageScope}}';
6
6
  const tanstackVersion = '1.170.1';
7
+ const rstackAgentSkillsCommit =
8
+ '61c948b42512e223bad44b83af4080eba48b2677';
7
9
  const modernPackages = [
8
10
  '@modern-js/app-tools',
9
11
  '@modern-js/plugin-bff',
10
12
  '@modern-js/plugin-tanstack',
11
13
  '@modern-js/runtime',
12
14
  ];
15
+ const baselineAgentSkills = [
16
+ 'rsbuild-best-practices',
17
+ 'rspack-best-practices',
18
+ 'rspack-tracing',
19
+ 'rsdoctor-analysis',
20
+ 'rslib-best-practices',
21
+ 'rslib-modern-package',
22
+ 'rstest-best-practices',
23
+ ];
13
24
 
14
25
  function readText(relativePath) {
15
26
  return fs.readFileSync(path.join(root, relativePath), 'utf-8');
@@ -30,9 +41,22 @@ function assertExists(relativePath) {
30
41
  }
31
42
 
32
43
  const requiredPaths = [
44
+ 'AGENTS.md',
33
45
  'package.json',
34
46
  'pnpm-workspace.yaml',
35
47
  'tsconfig.base.json',
48
+ '.agents/skills-lock.json',
49
+ '.agents/rstackjs-agent-skills-LICENSE',
50
+ '.agents/skills/rsbuild-best-practices/SKILL.md',
51
+ '.agents/skills/rspack-best-practices/SKILL.md',
52
+ '.agents/skills/rspack-tracing/SKILL.md',
53
+ '.agents/skills/rspack-tracing/references/tracing-guide.md',
54
+ '.agents/skills/rspack-tracing/scripts/analyze_trace.js',
55
+ '.agents/skills/rsdoctor-analysis/SKILL.md',
56
+ '.agents/skills/rsdoctor-analysis/references/rsdoctor-data-types.md',
57
+ '.agents/skills/rslib-best-practices/SKILL.md',
58
+ '.agents/skills/rslib-modern-package/SKILL.md',
59
+ '.agents/skills/rstest-best-practices/SKILL.md',
36
60
  'topology/reference-topology.json',
37
61
  'topology/ownership.json',
38
62
  'topology/local-overlays/development.json',
@@ -65,6 +89,7 @@ for (const requiredPath of requiredPaths) {
65
89
 
66
90
  const rootPackage = readJson('package.json');
67
91
  const packageSource = readJson('.modernjs/ultramodern-package-source.json');
92
+ const skillsLock = readJson('.agents/skills-lock.json');
68
93
  const expectedModernSpecifier =
69
94
  packageSource.strategy === 'install'
70
95
  ? packageSource.modernPackages?.specifier
@@ -83,6 +108,8 @@ function expectedModernDependency(packageName) {
83
108
 
84
109
  assert(rootPackage.private === true, 'Root package must be private');
85
110
  assert(rootPackage.modernjs?.preset === 'presetUltramodern', 'Root must declare presetUltramodern');
111
+ assert(rootPackage.packageManager === 'pnpm@11.1.2', 'Root must pin pnpm 11.1.2');
112
+ assert(rootPackage.engines?.pnpm === '>=11.0.0', 'Root must require pnpm >=11');
86
113
  assert(
87
114
  rootPackage.modernjs?.packageSource?.config ===
88
115
  './.modernjs/ultramodern-package-source.json',
@@ -117,6 +144,36 @@ assert(
117
144
  'Root must expose the ultramodern:check script',
118
145
  );
119
146
 
147
+ const agentsInstructions = readText('AGENTS.md');
148
+ assert(
149
+ agentsInstructions.includes('UltraModern Agent Contract') &&
150
+ agentsInstructions.includes('Required Skill Baseline'),
151
+ 'Root AGENTS.md must document the UltraModern agent contract',
152
+ );
153
+ assert(
154
+ skillsLock.source?.repository === 'https://github.com/rstackjs/agent-skills',
155
+ 'Agent skills lock must retain the Rstack skill source repository',
156
+ );
157
+ assert(
158
+ skillsLock.source?.commit === rstackAgentSkillsCommit,
159
+ 'Agent skills lock must pin the expected Rstack skill commit',
160
+ );
161
+ assert(
162
+ skillsLock.installDir === '.agents/skills',
163
+ 'Agent skills lock must use .agents/skills as installDir',
164
+ );
165
+ for (const skillName of baselineAgentSkills) {
166
+ assert(
167
+ skillsLock.baseline?.some(skill => skill.name === skillName),
168
+ `Agent skills lock must include ${skillName}`,
169
+ );
170
+ const skillContent = readText(`.agents/skills/${skillName}/SKILL.md`);
171
+ assert(
172
+ skillContent.includes(`name: ${skillName}`),
173
+ `${skillName} must contain matching skill metadata`,
174
+ );
175
+ }
176
+
120
177
  const appPackagePaths = [
121
178
  'apps/shell-super-app/package.json',
122
179
  'apps/remotes/remote-commerce/package.json',
@@ -268,6 +325,16 @@ assert(
268
325
  manifest.packageSource?.strategy === packageSource.strategy,
269
326
  'Template manifest must retain the generated package source strategy',
270
327
  );
328
+ assert(
329
+ manifest.agentSkills?.source?.commit === rstackAgentSkillsCommit,
330
+ 'Template manifest must retain the Rstack agent skills commit',
331
+ );
332
+ assert(
333
+ baselineAgentSkills.every(skillName =>
334
+ manifest.agentSkills?.baseline?.includes(skillName),
335
+ ),
336
+ 'Template manifest must list every baseline agent skill',
337
+ );
271
338
  assert(
272
339
  manifest.validation?.expectedCommands?.includes('pnpm run ultramodern:check'),
273
340
  'Template manifest must document the validation command',