specweave 1.0.261 → 1.0.263
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/.claude-plugin/README.md +0 -2
- package/CLAUDE.md +27 -27
- package/bin/specweave.js +14 -85
- package/dist/dashboard/assets/index-Cv1XUAKk.css +1 -0
- package/dist/dashboard/assets/index-DHOztQSu.js +11 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/src/adapters/README.md +1 -1
- package/dist/src/adapters/agents-md-generator.js +1 -1
- package/dist/src/adapters/agents-md-generator.js.map +1 -1
- package/dist/src/adapters/claude/README.md +8 -8
- package/dist/src/adapters/claude/adapter.js +2 -2
- package/dist/src/adapters/claude-md-generator.js +2 -2
- package/dist/src/adapters/claude-md-generator.js.map +1 -1
- package/dist/src/adapters/cursor/README.md +7 -7
- package/dist/src/adapters/generic/README.md +2 -2
- package/dist/src/cli/commands/create-increment.d.ts +1 -1
- package/dist/src/cli/commands/create-increment.js +1 -1
- package/dist/src/cli/commands/update.d.ts.map +1 -1
- package/dist/src/cli/commands/update.js +64 -1
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/cli/helpers/init/api-docs-config.js +7 -7
- package/dist/src/cli/helpers/init/api-docs-config.js.map +1 -1
- package/dist/src/core/config/types.d.ts +18 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js +4 -0
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/external-tools/external-items-display.d.ts.map +1 -1
- package/dist/src/core/external-tools/external-items-display.js +1 -11
- package/dist/src/core/external-tools/external-items-display.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +1 -1
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +2 -2
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/template-creator.d.ts +1 -1
- package/dist/src/core/increment/template-creator.js +4 -4
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts +2 -2
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.js +15 -5
- package/dist/src/core/lazy-loading/llm-plugin-detector.js.map +1 -1
- package/dist/src/core/living-docs/feature-consistency-validator.js +1 -1
- package/dist/src/core/living-docs/feature-consistency-validator.js.map +1 -1
- package/dist/src/core/living-docs/scaffolding/scaffold.js +3 -3
- package/dist/src/core/notifications/command-integration.d.ts.map +1 -1
- package/dist/src/core/notifications/command-integration.js +0 -1
- package/dist/src/core/notifications/command-integration.js.map +1 -1
- package/dist/src/core/reflection/reflect-handler.js +2 -2
- package/dist/src/core/reflection/reflect-handler.js.map +1 -1
- package/dist/src/core/validators/ac-presence-validator.d.ts +1 -1
- package/dist/src/core/validators/ac-presence-validator.js +3 -3
- package/dist/src/core/validators/ac-presence-validator.js.map +1 -1
- package/dist/src/dashboard/server/command-runner.d.ts.map +1 -1
- package/dist/src/dashboard/server/command-runner.js +2 -2
- package/dist/src/dashboard/server/command-runner.js.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.d.ts.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.js +22 -10
- package/dist/src/dashboard/server/dashboard-server.js.map +1 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.d.ts +9 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.js +140 -13
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.js.map +1 -1
- package/dist/src/dashboard/server/data/plugin-scanner.d.ts +1 -1
- package/dist/src/dashboard/server/data/plugin-scanner.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/plugin-scanner.js +2 -2
- package/dist/src/dashboard/server/data/plugin-scanner.js.map +1 -1
- package/dist/src/utils/agents-md-compiler.js +1 -1
- package/dist/src/utils/agents-md-compiler.js.map +1 -1
- package/dist/src/utils/find-project-root.d.ts +5 -4
- package/dist/src/utils/find-project-root.d.ts.map +1 -1
- package/dist/src/utils/find-project-root.js +8 -10
- package/dist/src/utils/find-project-root.js.map +1 -1
- package/dist/src/utils/generate-skills-index.js +3 -3
- package/dist/src/utils/notification-constants.js +1 -1
- package/dist/src/utils/notification-constants.js.map +1 -1
- package/package.json +1 -1
- package/plugins/FINAL-AUDIT-RECOMMENDATIONS.md +3 -3
- package/plugins/specweave/PLUGIN.md +0 -22
- package/plugins/specweave/commands/analytics.md +1 -1
- package/plugins/specweave/commands/discrepancies.md +0 -1
- package/plugins/specweave/commands/living-docs.md +0 -1
- package/plugins/specweave/commands/reconcile.md +1 -1
- package/plugins/specweave/hooks/hooks.json +19 -0
- package/plugins/specweave/hooks/pre-compact.sh +39 -0
- package/plugins/specweave/hooks/stop-sync.sh +23 -1
- package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +4 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +193 -59
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +83 -0
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +7 -0
- package/plugins/specweave/hooks/v2/guards/spec-template-enforcement-guard.sh +1 -1
- package/plugins/specweave/hooks/v2/handlers/ac-sync-dispatcher.sh +25 -6
- package/plugins/specweave/hooks/v2/handlers/universal-auto-create-dispatcher.sh +21 -3
- package/plugins/specweave/hooks/v2/lib/check-provider-enabled.sh +52 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +2 -2
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/scripts/track-analytics.sh +4 -0
- package/plugins/specweave/skills/do/SKILL.md +1 -1
- package/plugins/specweave/skills/done/SKILL.md +1 -1
- package/plugins/specweave/skills/framework/SKILL.md +4 -4
- package/plugins/specweave/skills/increment/SKILL.md +192 -25
- package/plugins/specweave/skills/next/SKILL.md +36 -630
- package/plugins/specweave/skills/pm/phases/00-deep-interview.md +2 -2
- package/plugins/specweave/skills/progress-sync/SKILL.md +7 -25
- package/plugins/specweave/skills/spec-generator/SKILL.md +44 -626
- package/plugins/specweave/skills/tdd-green/SKILL.md +10 -798
- package/plugins/specweave/skills/tdd-red/SKILL.md +8 -136
- package/plugins/specweave/skills/tdd-refactor/SKILL.md +15 -147
- package/plugins/specweave-github/hooks/github-auto-create-handler.sh +23 -5
- package/src/templates/AGENTS.md.template +11 -11
- package/src/templates/CLAUDE.md.template +1 -1
- package/dist/dashboard/assets/index-CDl14O5G.css +0 -1
- package/dist/dashboard/assets/index-CmqBqnWd.js +0 -11
- package/plugins/specweave/commands/api-docs.md +0 -672
- package/plugins/specweave/commands/check-hooks.md +0 -241
- package/plugins/specweave/commands/embed-acs.md +0 -445
- package/plugins/specweave/commands/external.md +0 -145
- package/plugins/specweave/commands/import-docs.md +0 -212
- package/plugins/specweave/commands/migrate-config.md +0 -104
- package/plugins/specweave/commands/notifications.md +0 -94
- package/plugins/specweave/commands/plugin-validator.md +0 -429
- package/plugins/specweave/commands/revert-wip-limit.md +0 -82
- package/plugins/specweave/commands/sync-acs.md +0 -342
- package/plugins/specweave/commands/sync-specs.md +0 -339
- package/plugins/specweave/commands/sync-tasks.md +0 -255
- package/plugins/specweave/commands/update-scope.md +0 -351
- package/plugins/specweave/commands/validate-features.md +0 -207
- package/plugins/specweave/skills/archive-increments/SKILL.md +0 -209
- package/plugins/specweave/skills/code-review/SKILL.md +0 -598
- package/plugins/specweave/skills/increment-planner/SKILL.md +0 -238
- package/plugins/specweave/skills/increment-work-router/SKILL.md +0 -562
- package/plugins/specweave/skills/multi-project-spec-mapper/SKILL.md +0 -423
- package/plugins/specweave/skills/pm-closure-validation/SKILL.md +0 -542
- package/plugins/specweave/skills/smart-reopen-detector/SKILL.md +0 -245
- package/plugins/specweave/skills/tdd-orchestrator/SKILL.md +0 -228
- package/plugins/specweave/skills/umbrella-repo-detector/SKILL.md +0 -301
|
@@ -10,8 +10,6 @@ description: Write failing tests that define expected behavior. Use when saying
|
|
|
10
10
|
|
|
11
11
|
Write comprehensive failing tests following TDD red phase principles.
|
|
12
12
|
|
|
13
|
-
[Extended thinking: Generates failing tests that properly define expected behavior using test-automator agent.]
|
|
14
|
-
|
|
15
13
|
## Role
|
|
16
14
|
|
|
17
15
|
Generate failing tests using Task tool with subagent_type="unit-testing::test-automator".
|
|
@@ -22,56 +20,13 @@ Generate failing tests using Task tool with subagent_type="unit-testing::test-au
|
|
|
22
20
|
|
|
23
21
|
## Core Requirements
|
|
24
22
|
|
|
25
|
-
1. **Test Structure
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- Isolated fixtures with no interdependencies
|
|
30
|
-
|
|
31
|
-
2. **Behavior Coverage**
|
|
32
|
-
- Happy path scenarios
|
|
33
|
-
- Edge cases (empty, null, boundary values)
|
|
34
|
-
- Error handling and exceptions
|
|
35
|
-
- Concurrent access (if applicable)
|
|
36
|
-
|
|
37
|
-
3. **Failure Verification**
|
|
38
|
-
- Tests MUST fail when run
|
|
39
|
-
- Failures for RIGHT reasons (not syntax/import errors)
|
|
40
|
-
- Meaningful diagnostic error messages
|
|
41
|
-
- No cascading failures
|
|
42
|
-
|
|
43
|
-
4. **Test Categories**
|
|
44
|
-
- Unit: Isolated component behavior
|
|
45
|
-
- Integration: Component interaction
|
|
46
|
-
- Contract: API/interface contracts
|
|
47
|
-
- Property: Mathematical invariants
|
|
48
|
-
|
|
49
|
-
## Framework Patterns
|
|
50
|
-
|
|
51
|
-
**JavaScript/TypeScript (Jest/Vitest)**
|
|
52
|
-
- Mock dependencies with `vi.fn()` or `jest.fn()`
|
|
53
|
-
- Use `@testing-library` for React components
|
|
54
|
-
- Property tests with `fast-check`
|
|
55
|
-
|
|
56
|
-
**Python (pytest)**
|
|
57
|
-
- Fixtures with appropriate scopes
|
|
58
|
-
- Parametrize for multiple test cases
|
|
59
|
-
- Hypothesis for property-based tests
|
|
60
|
-
|
|
61
|
-
**Go**
|
|
62
|
-
- Table-driven tests with subtests
|
|
63
|
-
- `t.Parallel()` for parallel execution
|
|
64
|
-
- Use `testify/assert` for cleaner assertions
|
|
65
|
-
|
|
66
|
-
**Ruby (RSpec)**
|
|
67
|
-
- `let` for lazy loading, `let!` for eager
|
|
68
|
-
- Contexts for different scenarios
|
|
69
|
-
- Shared examples for common behavior
|
|
23
|
+
1. **Test Structure**: Framework-appropriate setup, Arrange-Act-Assert, should_X_when_Y naming, isolated fixtures
|
|
24
|
+
2. **Behavior Coverage**: Happy path, edge cases (empty/null/boundary), error handling, concurrent access
|
|
25
|
+
3. **Failure Verification**: Tests MUST fail when run, for RIGHT reasons (not syntax/import errors), meaningful diagnostics
|
|
26
|
+
4. **Test Categories**: Unit (isolated), Integration (interaction), Contract (API/interface), Property (invariants)
|
|
70
27
|
|
|
71
28
|
## CLI Integration Test Patterns
|
|
72
29
|
|
|
73
|
-
When testing CLI commands, hooks, or terminal tools, use these specialized patterns:
|
|
74
|
-
|
|
75
30
|
**Temp Home Isolation** (prevents touching real ~/.specweave/):
|
|
76
31
|
```typescript
|
|
77
32
|
import { withIsolatedHome, getIsolatedEnv } from '../test-utils/temp-home.js';
|
|
@@ -89,7 +44,7 @@ it('should run CLI command in isolated environment', async () => {
|
|
|
89
44
|
});
|
|
90
45
|
```
|
|
91
46
|
|
|
92
|
-
**Hook Execution Testing
|
|
47
|
+
**Hook Execution Testing**:
|
|
93
48
|
```typescript
|
|
94
49
|
import { HookTestHarness } from '../test-utils/hook-test-harness.js';
|
|
95
50
|
import { extractJson } from '../test-utils/normalize-output.js';
|
|
@@ -102,97 +57,14 @@ it('should return approve decision from hook', async () => {
|
|
|
102
57
|
});
|
|
103
58
|
```
|
|
104
59
|
|
|
105
|
-
**Process Spawning
|
|
106
|
-
- Always use `getCleanEnv()` or `getIsolatedEnv()` to strip NODE_OPTIONS
|
|
107
|
-
- Set timeout: `{ timeout: 30000 }` for CLI tests
|
|
108
|
-
- Capture both stdout AND stderr
|
|
109
|
-
- Use `normalizeOutput()` before assertions
|
|
110
|
-
- Use `extractJson()` for mixed JSON/text output
|
|
111
|
-
- Create temp working directories with `createIsolatedTestDir()`
|
|
112
|
-
|
|
113
|
-
**Exit Code Verification**:
|
|
114
|
-
```typescript
|
|
115
|
-
try {
|
|
116
|
-
await execAsync('node bin/cli.js bad-command', { env: getIsolatedEnv(home) });
|
|
117
|
-
expect.unreachable('Expected non-zero exit');
|
|
118
|
-
} catch (error: any) {
|
|
119
|
-
expect(error.code).not.toBe(0);
|
|
120
|
-
expect(normalizeOutput(error.stderr)).toContain('Unknown command');
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Quality Checklist
|
|
125
|
-
|
|
126
|
-
- Readable test names documenting intent
|
|
127
|
-
- One behavior per test
|
|
128
|
-
- No implementation leakage
|
|
129
|
-
- Meaningful test data (not 'foo'/'bar')
|
|
130
|
-
- Tests serve as living documentation
|
|
131
|
-
|
|
132
|
-
## Anti-Patterns to Avoid
|
|
133
|
-
|
|
134
|
-
- Tests passing immediately
|
|
135
|
-
- Testing implementation vs behavior
|
|
136
|
-
- Complex setup code
|
|
137
|
-
- Multiple responsibilities per test
|
|
138
|
-
- Brittle tests tied to specifics
|
|
139
|
-
|
|
140
|
-
## Edge Case Categories
|
|
141
|
-
|
|
142
|
-
- **Null/Empty**: undefined, null, empty string/array/object
|
|
143
|
-
- **Boundaries**: min/max values, single element, capacity limits
|
|
144
|
-
- **Special Cases**: Unicode, whitespace, special characters
|
|
145
|
-
- **State**: Invalid transitions, concurrent modifications
|
|
146
|
-
- **Errors**: Network failures, timeouts, permissions
|
|
147
|
-
|
|
148
|
-
## Output Requirements
|
|
149
|
-
|
|
150
|
-
- Complete test files with imports
|
|
151
|
-
- Documentation of test purpose
|
|
152
|
-
- Commands to run and verify failures
|
|
153
|
-
- Metrics: test count, coverage areas
|
|
154
|
-
- Next steps for green phase"
|
|
60
|
+
**Process Spawning**: Use `getCleanEnv()`/`getIsolatedEnv()` to strip NODE_OPTIONS. Set `{ timeout: 30000 }`. Use `normalizeOutput()` and `extractJson()`.
|
|
155
61
|
|
|
156
62
|
## Validation
|
|
157
63
|
|
|
158
64
|
After generation:
|
|
159
|
-
1. Run tests
|
|
65
|
+
1. Run tests — confirm they fail
|
|
160
66
|
2. Verify helpful failure messages
|
|
161
67
|
3. Check test independence
|
|
162
|
-
4. Ensure comprehensive coverage
|
|
163
|
-
|
|
164
|
-
## Example (Minimal)
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
// auth.service.test.ts
|
|
168
|
-
describe('AuthService', () => {
|
|
169
|
-
let authService: AuthService;
|
|
170
|
-
let mockUserRepo: jest.Mocked<UserRepository>;
|
|
171
|
-
|
|
172
|
-
beforeEach(() => {
|
|
173
|
-
mockUserRepo = { findByEmail: jest.fn() } as any;
|
|
174
|
-
authService = new AuthService(mockUserRepo);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('should_return_token_when_valid_credentials', async () => {
|
|
178
|
-
const user = { id: '1', email: 'test@example.com', passwordHash: 'hashed' };
|
|
179
|
-
mockUserRepo.findByEmail.mockResolvedValue(user);
|
|
180
|
-
|
|
181
|
-
const result = await authService.authenticate('test@example.com', 'pass');
|
|
182
|
-
|
|
183
|
-
expect(result.success).toBe(true);
|
|
184
|
-
expect(result.token).toBeDefined();
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('should_fail_when_user_not_found', async () => {
|
|
188
|
-
mockUserRepo.findByEmail.mockResolvedValue(null);
|
|
189
|
-
|
|
190
|
-
const result = await authService.authenticate('none@example.com', 'pass');
|
|
191
|
-
|
|
192
|
-
expect(result.success).toBe(false);
|
|
193
|
-
expect(result.error).toBe('INVALID_CREDENTIALS');
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
```
|
|
68
|
+
4. Ensure comprehensive coverage"
|
|
197
69
|
|
|
198
70
|
Test requirements: $ARGUMENTS
|
|
@@ -4,9 +4,7 @@ description: Refactor code with test safety net to improve quality. Use when say
|
|
|
4
4
|
|
|
5
5
|
# TDD Refactor Phase - Improve Code Quality
|
|
6
6
|
|
|
7
|
-
Refactor code with confidence using comprehensive test safety net
|
|
8
|
-
|
|
9
|
-
[Extended thinking: This tool uses the tdd-orchestrator agent (opus model) for sophisticated refactoring while maintaining all tests green. It applies design patterns, improves code quality, and optimizes performance with the safety of comprehensive test coverage.]
|
|
7
|
+
Refactor code with confidence using comprehensive test safety net.
|
|
10
8
|
|
|
11
9
|
## Usage
|
|
12
10
|
|
|
@@ -14,158 +12,28 @@ Use Task tool with subagent_type="general-purpose" to perform safe refactoring.
|
|
|
14
12
|
|
|
15
13
|
Prompt: "Refactor this code while keeping all tests green: $ARGUMENTS. Apply TDD refactor phase:
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- Document current performance metrics
|
|
23
|
-
- Create incremental refactoring plan
|
|
24
|
-
|
|
25
|
-
**2. Code Smell Detection**
|
|
26
|
-
- Duplicated code → Extract methods/classes
|
|
27
|
-
- Long methods → Decompose into focused functions
|
|
28
|
-
- Large classes → Split responsibilities
|
|
29
|
-
- Long parameter lists → Parameter objects
|
|
30
|
-
- Feature Envy → Move methods to appropriate classes
|
|
31
|
-
- Primitive Obsession → Value objects
|
|
32
|
-
- Switch statements → Polymorphism
|
|
33
|
-
- Dead code → Remove
|
|
34
|
-
|
|
35
|
-
**3. Design Patterns**
|
|
36
|
-
- Apply Creational (Factory, Builder, Singleton)
|
|
37
|
-
- Apply Structural (Adapter, Facade, Decorator)
|
|
38
|
-
- Apply Behavioral (Strategy, Observer, Command)
|
|
39
|
-
- Apply Domain (Repository, Service, Value Objects)
|
|
40
|
-
- Use patterns only where they add clear value
|
|
41
|
-
|
|
42
|
-
**4. SOLID Principles**
|
|
43
|
-
- Single Responsibility: One reason to change
|
|
44
|
-
- Open/Closed: Open for extension, closed for modification
|
|
45
|
-
- Liskov Substitution: Subtypes substitutable
|
|
46
|
-
- Interface Segregation: Small, focused interfaces
|
|
47
|
-
- Dependency Inversion: Depend on abstractions
|
|
48
|
-
|
|
49
|
-
**5. Refactoring Techniques**
|
|
50
|
-
- Extract Method/Variable/Interface
|
|
51
|
-
- Inline unnecessary indirection
|
|
52
|
-
- Rename for clarity
|
|
53
|
-
- Move Method/Field to appropriate classes
|
|
54
|
-
- Replace Magic Numbers with constants
|
|
55
|
-
- Encapsulate fields
|
|
56
|
-
- Replace Conditional with Polymorphism
|
|
57
|
-
- Introduce Null Object
|
|
58
|
-
|
|
59
|
-
**6. Performance Optimization**
|
|
60
|
-
- Profile to identify bottlenecks
|
|
61
|
-
- Optimize algorithms and data structures
|
|
62
|
-
- Implement caching where beneficial
|
|
63
|
-
- Reduce database queries (N+1 elimination)
|
|
64
|
-
- Lazy loading and pagination
|
|
65
|
-
- Always measure before and after
|
|
66
|
-
|
|
67
|
-
**7. Incremental Steps**
|
|
68
|
-
- Make small, atomic changes
|
|
69
|
-
- Run tests after each modification
|
|
70
|
-
- Commit after each successful refactoring
|
|
71
|
-
- Keep refactoring separate from behavior changes
|
|
72
|
-
- Use scaffolding when needed
|
|
73
|
-
|
|
74
|
-
**8. Architecture Evolution**
|
|
75
|
-
- Layer separation and dependency management
|
|
76
|
-
- Module boundaries and interface definition
|
|
77
|
-
- Event-driven patterns for decoupling
|
|
78
|
-
- Database access pattern optimization
|
|
79
|
-
|
|
80
|
-
**9. Safety Verification**
|
|
81
|
-
- Run full test suite after each change
|
|
82
|
-
- Performance regression testing
|
|
83
|
-
- Mutation testing for test effectiveness
|
|
84
|
-
- Rollback plan for major changes
|
|
85
|
-
|
|
86
|
-
**10. Advanced Patterns**
|
|
87
|
-
- Strangler Fig: Gradual legacy replacement
|
|
88
|
-
- Branch by Abstraction: Large-scale changes
|
|
89
|
-
- Parallel Change: Expand-contract pattern
|
|
90
|
-
- Mikado Method: Dependency graph navigation
|
|
91
|
-
|
|
92
|
-
## Output Requirements
|
|
15
|
+
1. **Pre-Assessment**: Run tests to establish green baseline, analyze code smells, document current metrics
|
|
16
|
+
2. **Code Smell Detection**: Duplicated code, long methods, large classes, long parameter lists, feature envy, dead code
|
|
17
|
+
3. **Refactoring Techniques**: Extract Method/Variable/Interface, inline unnecessary indirection, rename for clarity, move to appropriate classes, replace conditionals with polymorphism
|
|
18
|
+
4. **Incremental Steps**: Small atomic changes, run tests after each modification, commit after each successful refactoring, keep separate from behavior changes
|
|
19
|
+
5. **Safety Verification**: Run full test suite after each change, check for performance regressions, maintain/improve code coverage
|
|
93
20
|
|
|
21
|
+
Output:
|
|
94
22
|
- Refactored code with improvements applied
|
|
95
23
|
- Test results (all green)
|
|
96
24
|
- Before/after metrics comparison
|
|
97
|
-
- Applied refactoring techniques list
|
|
98
|
-
- Performance improvement measurements
|
|
99
|
-
- Remaining technical debt assessment
|
|
25
|
+
- Applied refactoring techniques list"
|
|
100
26
|
|
|
101
27
|
## Safety Checklist
|
|
102
28
|
|
|
103
29
|
Before committing:
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
- ✓ Documentation updated
|
|
109
|
-
|
|
110
|
-
## Recovery Protocol
|
|
111
|
-
|
|
112
|
-
If tests fail:
|
|
113
|
-
- Immediately revert last change
|
|
114
|
-
- Identify breaking refactoring
|
|
115
|
-
- Apply smaller incremental changes
|
|
116
|
-
- Use version control for safe experimentation
|
|
117
|
-
|
|
118
|
-
## Example: Extract Method Pattern
|
|
119
|
-
|
|
120
|
-
**Before:**
|
|
121
|
-
```typescript
|
|
122
|
-
class OrderProcessor {
|
|
123
|
-
processOrder(order: Order): ProcessResult {
|
|
124
|
-
// Validation
|
|
125
|
-
if (!order.customerId || order.items.length === 0) {
|
|
126
|
-
return { success: false, error: "Invalid order" };
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Calculate totals
|
|
130
|
-
let subtotal = 0;
|
|
131
|
-
for (const item of order.items) {
|
|
132
|
-
subtotal += item.price * item.quantity;
|
|
133
|
-
}
|
|
134
|
-
let total = subtotal + (subtotal * 0.08) + (subtotal > 100 ? 0 : 15);
|
|
135
|
-
|
|
136
|
-
// Process payment...
|
|
137
|
-
// Update inventory...
|
|
138
|
-
// Send confirmation...
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**After:**
|
|
144
|
-
```typescript
|
|
145
|
-
class OrderProcessor {
|
|
146
|
-
async processOrder(order: Order): Promise<ProcessResult> {
|
|
147
|
-
const validation = this.validateOrder(order);
|
|
148
|
-
if (!validation.isValid) return ProcessResult.failure(validation.error);
|
|
149
|
-
|
|
150
|
-
const orderTotal = OrderTotal.calculate(order);
|
|
151
|
-
const inventoryCheck = await this.inventoryService.checkAvailability(order.items);
|
|
152
|
-
if (!inventoryCheck.available) return ProcessResult.failure(inventoryCheck.reason);
|
|
153
|
-
|
|
154
|
-
await this.paymentService.processPayment(order.paymentMethod, orderTotal.total);
|
|
155
|
-
await this.inventoryService.reserveItems(order.items);
|
|
156
|
-
await this.notificationService.sendOrderConfirmation(order, orderTotal);
|
|
157
|
-
|
|
158
|
-
return ProcessResult.success(order.id, orderTotal.total);
|
|
159
|
-
}
|
|
30
|
+
- All tests pass (100% green)
|
|
31
|
+
- No functionality regression
|
|
32
|
+
- Performance metrics acceptable
|
|
33
|
+
- Code coverage maintained/improved
|
|
160
34
|
|
|
161
|
-
|
|
162
|
-
if (!order.customerId) return ValidationResult.invalid("Customer ID required");
|
|
163
|
-
if (order.items.length === 0) return ValidationResult.invalid("Order must contain items");
|
|
164
|
-
return ValidationResult.valid();
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
```
|
|
35
|
+
## Recovery
|
|
168
36
|
|
|
169
|
-
|
|
37
|
+
If tests fail: immediately revert last change, identify breaking refactoring, apply smaller incremental changes.
|
|
170
38
|
|
|
171
|
-
Code to refactor: $ARGUMENTS
|
|
39
|
+
Code to refactor: $ARGUMENTS
|
|
@@ -54,9 +54,22 @@ log() {
|
|
|
54
54
|
command -v gh &>/dev/null || { log "gh CLI not found"; exit 0; }
|
|
55
55
|
command -v jq &>/dev/null || { log "jq not found"; exit 0; }
|
|
56
56
|
|
|
57
|
-
# Check GitHub sync enabled
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
# Check GitHub sync enabled (shared 3-method detection)
|
|
58
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
59
|
+
SHARED_LIB_PATHS=(
|
|
60
|
+
"$SCRIPT_DIR/../../specweave/hooks/v2/lib/check-provider-enabled.sh"
|
|
61
|
+
"$SCRIPT_DIR/../../../specweave/hooks/v2/lib/check-provider-enabled.sh"
|
|
62
|
+
)
|
|
63
|
+
for _lib in "${SHARED_LIB_PATHS[@]}"; do
|
|
64
|
+
[[ -f "$_lib" ]] && { source "$_lib"; break; }
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
if type check_provider_enabled &>/dev/null; then
|
|
68
|
+
check_provider_enabled "$CONFIG_PATH" "github" || { log "GitHub sync not enabled"; exit 0; }
|
|
69
|
+
else
|
|
70
|
+
GH_ENABLED=$(jq -r '.sync.github.enabled // false' "$CONFIG_PATH" 2>/dev/null)
|
|
71
|
+
[[ "$GH_ENABLED" != "true" ]] && { log "GitHub sync not enabled"; exit 0; }
|
|
72
|
+
fi
|
|
60
73
|
|
|
61
74
|
# Check auto-create enabled (either autoSync OR auto_create_github_issue)
|
|
62
75
|
AUTO_SYNC=$(jq -r '.sync.autoSync // false' "$CONFIG_PATH" 2>/dev/null)
|
|
@@ -125,8 +138,13 @@ fi
|
|
|
125
138
|
# ============================================================================
|
|
126
139
|
|
|
127
140
|
if [[ -f "$META_PATH" ]]; then
|
|
128
|
-
# Check
|
|
129
|
-
ISSUE_COUNT=$(jq '
|
|
141
|
+
# Check BOTH new (externalLinks) and old (github.issues[]) formats for existing issues
|
|
142
|
+
ISSUE_COUNT=$(jq '
|
|
143
|
+
[
|
|
144
|
+
(.externalLinks.github.issues // {} | to_entries[] | select(.value.issueNumber != null)),
|
|
145
|
+
(.github.issues // [] | .[] | select(.number != null))
|
|
146
|
+
] | length
|
|
147
|
+
' "$META_PATH" 2>/dev/null || echo 0)
|
|
130
148
|
if (( ISSUE_COUNT > 0 )); then
|
|
131
149
|
log "Issues already exist for $INC_ID ($ISSUE_COUNT). Skipping."
|
|
132
150
|
exit 0
|
|
@@ -304,7 +304,7 @@ git diff # Review what actually changed
|
|
|
304
304
|
| `/sw:done 0001` | Close increment (validates gates) |
|
|
305
305
|
| `/sw:progress` | Show task completion status |
|
|
306
306
|
| `/sw:validate 0001` | Quality check before closing |
|
|
307
|
-
| `/sw:sync
|
|
307
|
+
| `/sw:progress-sync` | Sync tasks.md with reality |
|
|
308
308
|
| `/sw:sync-docs update` | Sync to living docs |
|
|
309
309
|
|
|
310
310
|
### Plugin Commands (when installed)
|
|
@@ -444,7 +444,7 @@ This gives you the SAME experience as Claude Code with MCP, but deterministic an
|
|
|
444
444
|
# Change: - [ ] AC-US1-01 → - [x] AC-US1-01
|
|
445
445
|
|
|
446
446
|
# Step 3: Sync to external tools (if configured)
|
|
447
|
-
/sw:sync
|
|
447
|
+
/sw:progress-sync
|
|
448
448
|
/sw-github:sync <increment-id> # If GitHub enabled
|
|
449
449
|
/sw-jira:sync <increment-id> # If Jira enabled
|
|
450
450
|
```
|
|
@@ -482,7 +482,7 @@ This gives you the SAME experience as Claude Code with MCP, but deterministic an
|
|
|
482
482
|
# After any edit to spec.md or tasks.md:
|
|
483
483
|
|
|
484
484
|
# Sync status line cache
|
|
485
|
-
/sw:sync
|
|
485
|
+
/sw:progress-sync
|
|
486
486
|
|
|
487
487
|
# If external tools configured, sync progress
|
|
488
488
|
/sw-github:sync <increment-id>
|
|
@@ -560,7 +560,7 @@ cat plugins/specweave/commands/increment.md
|
|
|
560
560
|
├─────────────────────────────────────────────────────────────┤
|
|
561
561
|
│ 1. Update tasks.md: [ ] → [x] │
|
|
562
562
|
│ 2. Update spec.md ACs if satisfied: [ ] → [x] │
|
|
563
|
-
│ 3. Run: /sw:sync
|
|
563
|
+
│ 3. Run: /sw:progress-sync │
|
|
564
564
|
│ 4. Run: /sw-github:sync <id> (if GitHub configured) │
|
|
565
565
|
│ 5. If all ACs for US done: /sw:sync-docs update │
|
|
566
566
|
└─────────────────────────────────────────────────────────────┘
|
|
@@ -609,7 +609,7 @@ cat plugins/specweave/commands/increment.md
|
|
|
609
609
|
|
|
610
610
|
| Command | What It Does | When to Run |
|
|
611
611
|
|---------|--------------|-------------|
|
|
612
|
-
| `/sw:sync
|
|
612
|
+
| `/sw:progress-sync` | Recalculates progress from tasks.md | After editing tasks.md |
|
|
613
613
|
| `/sw:sync-docs update` | Updates living docs from increment | After US complete |
|
|
614
614
|
| `/sw-github:sync <id>` | Syncs progress to GitHub issue | After each task |
|
|
615
615
|
| `/sw-github:close-issue <id>` | Closes GitHub issue | On increment done |
|
|
@@ -635,7 +635,7 @@ TASK COMPLETED
|
|
|
635
635
|
│
|
|
636
636
|
▼
|
|
637
637
|
┌─────────────────────────────┐
|
|
638
|
-
│ 3. /sw:sync
|
|
638
|
+
│ 3. /sw:progress-sync │
|
|
639
639
|
│ Updates progress cache │
|
|
640
640
|
└─────────────────────────────┘
|
|
641
641
|
│
|
|
@@ -755,10 +755,10 @@ Skills don't auto-activate. You must manually load them:
|
|
|
755
755
|
ls plugins/specweave*/skills/
|
|
756
756
|
|
|
757
757
|
# Step 2: Read the skill file
|
|
758
|
-
cat plugins/specweave/skills/increment
|
|
758
|
+
cat plugins/specweave/skills/increment/SKILL.md
|
|
759
759
|
|
|
760
760
|
# Step 3: Tell AI to follow the skill's workflow
|
|
761
|
-
"Follow the increment
|
|
761
|
+
"Follow the increment skill workflow to create my feature"
|
|
762
762
|
|
|
763
763
|
# Step 4: AI reads skill content and follows instructions
|
|
764
764
|
```
|
|
@@ -782,7 +782,7 @@ AI: [Gets output: {"level":1,"projects":[{"id":"my-app"}]}]
|
|
|
782
782
|
AI: [Stores: RESOLVED_PROJECT = "my-app"]
|
|
783
783
|
|
|
784
784
|
# Then follow the skill workflow
|
|
785
|
-
AI: [Reads plugins/specweave/skills/increment
|
|
785
|
+
AI: [Reads plugins/specweave/skills/increment/SKILL.md]
|
|
786
786
|
AI: [Follows PM workflow: research → spec → plan → tasks]
|
|
787
787
|
AI: [Creates .specweave/increments/0001-auth/spec.md with **Project**: my-app per US!]
|
|
788
788
|
```
|
|
@@ -935,7 +935,7 @@ cat plugins/specweave/commands/increment.md
|
|
|
935
935
|
|
|
936
936
|
**Solution** (run after EVERY task in non-Claude tools):
|
|
937
937
|
```bash
|
|
938
|
-
/sw:sync
|
|
938
|
+
/sw:progress-sync # Update tasks.md
|
|
939
939
|
/sw:sync-docs update # Sync living docs
|
|
940
940
|
/sw-github:sync <increment-id> # Sync to GitHub
|
|
941
941
|
```
|
|
@@ -959,7 +959,7 @@ mv *.md .specweave/increments/$CURRENT/reports/
|
|
|
959
959
|
**Status**: [ ] pending → **Status**: [x] completed
|
|
960
960
|
```
|
|
961
961
|
|
|
962
|
-
Or run: `/sw:sync
|
|
962
|
+
Or run: `/sw:progress-sync`
|
|
963
963
|
|
|
964
964
|
### Context Explosion / Crashes
|
|
965
965
|
|
|
@@ -208,7 +208,7 @@ When `testing.defaultTestMode: "TDD"` in config.json: RED→GREEN→REFACTOR. Us
|
|
|
208
208
|
|-------|-----|
|
|
209
209
|
| Skills missing | Restart Claude Code |
|
|
210
210
|
| Plugins outdated | `specweave refresh-marketplace` |
|
|
211
|
-
| Out of sync | `/sw:sync-
|
|
211
|
+
| Out of sync | `/sw:sync-progress` |
|
|
212
212
|
| Session stuck | `rm -f .specweave/state/*.lock` + restart |
|
|
213
213
|
<!-- /SECTION -->
|
|
214
214
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-400:oklch(70.4% .191 22.216);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-yellow-400:oklch(85.2% .199 91.936);--color-green-400:oklch(79.2% .209 151.711);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-cyan-400:oklch(78.9% .154 211.53);--color-cyan-500:oklch(71.5% .143 215.221);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-indigo-300:oklch(78.5% .115 274.713);--color-indigo-400:oklch(67.3% .182 276.935);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-rose-300:oklch(81% .117 11.638);--color-rose-400:oklch(71.2% .194 13.428);--color-rose-500:oklch(64.5% .246 16.439);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-gray-950:oklch(13% .028 261.692);--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wider:.05em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-0\.5{top:calc(var(--spacing)*.5)}.left-0\.5{left:calc(var(--spacing)*.5)}.left-\[18px\]{left:18px}.mx-auto{margin-inline:auto}.my-2{margin-block:calc(var(--spacing)*2)}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mb-0\.5{margin-bottom:calc(var(--spacing)*.5)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-1\.5{margin-bottom:calc(var(--spacing)*1.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-10{margin-left:calc(var(--spacing)*10)}.block{display:block}.flex{display:flex}.grid{display:grid}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-1\.5{height:calc(var(--spacing)*1.5)}.h-2{height:calc(var(--spacing)*2)}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-12{height:calc(var(--spacing)*12)}.h-14{height:calc(var(--spacing)*14)}.h-40{height:calc(var(--spacing)*40)}.h-64{height:calc(var(--spacing)*64)}.h-\[18px\]{height:18px}.h-full{height:100%}.h-screen{height:100vh}.max-h-48{max-height:calc(var(--spacing)*48)}.max-h-64{max-height:calc(var(--spacing)*64)}.max-h-\[500px\]{max-height:500px}.min-h-screen{min-height:100vh}.w-1\.5{width:calc(var(--spacing)*1.5)}.w-2{width:calc(var(--spacing)*2)}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-9{width:calc(var(--spacing)*9)}.w-10{width:calc(var(--spacing)*10)}.w-12{width:calc(var(--spacing)*12)}.w-14{width:calc(var(--spacing)*14)}.w-16{width:calc(var(--spacing)*16)}.w-24{width:calc(var(--spacing)*24)}.w-28{width:calc(var(--spacing)*28)}.w-48{width:calc(var(--spacing)*48)}.w-56{width:calc(var(--spacing)*56)}.w-full{width:100%}.w-px{width:1px}.max-w-\[120px\]{max-width:120px}.max-w-\[180px\]{max-width:180px}.max-w-\[200px\]{max-width:200px}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\[18px\]{min-width:18px}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.-rotate-90{rotate:-90deg}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[1fr\,80px\,80px\,120px\]{grid-template-columns:1fr,80px,80px,120px}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-800\/50>:not(:last-child)){border-color:#1e293980}@supports (color:color-mix(in lab,red,red)){:where(.divide-gray-800\/50>:not(:last-child)){border-color:color-mix(in oklab,var(--color-gray-800)50%,transparent)}}.self-center{align-self:center}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-amber-500\/20{border-color:#f99c0033}@supports (color:color-mix(in lab,red,red)){.border-amber-500\/20{border-color:color-mix(in oklab,var(--color-amber-500)20%,transparent)}}.border-amber-500\/50{border-color:#f99c0080}@supports (color:color-mix(in lab,red,red)){.border-amber-500\/50{border-color:color-mix(in oklab,var(--color-amber-500)50%,transparent)}}.border-cyan-500\/20{border-color:#00b7d733}@supports (color:color-mix(in lab,red,red)){.border-cyan-500\/20{border-color:color-mix(in oklab,var(--color-cyan-500)20%,transparent)}}.border-emerald-500{border-color:var(--color-emerald-500)}.border-emerald-500\/20{border-color:#00bb7f33}@supports (color:color-mix(in lab,red,red)){.border-emerald-500\/20{border-color:color-mix(in oklab,var(--color-emerald-500)20%,transparent)}}.border-emerald-500\/30{border-color:#00bb7f4d}@supports (color:color-mix(in lab,red,red)){.border-emerald-500\/30{border-color:color-mix(in oklab,var(--color-emerald-500)30%,transparent)}}.border-gray-600{border-color:var(--color-gray-600)}.border-gray-700{border-color:var(--color-gray-700)}.border-gray-800{border-color:var(--color-gray-800)}.border-gray-800\/50{border-color:#1e293980}@supports (color:color-mix(in lab,red,red)){.border-gray-800\/50{border-color:color-mix(in oklab,var(--color-gray-800)50%,transparent)}}.border-indigo-500{border-color:var(--color-indigo-500)}.border-indigo-500\/20{border-color:#625fff33}@supports (color:color-mix(in lab,red,red)){.border-indigo-500\/20{border-color:color-mix(in oklab,var(--color-indigo-500)20%,transparent)}}.border-indigo-500\/30{border-color:#625fff4d}@supports (color:color-mix(in lab,red,red)){.border-indigo-500\/30{border-color:color-mix(in oklab,var(--color-indigo-500)30%,transparent)}}.border-rose-500{border-color:var(--color-rose-500)}.border-rose-500\/20{border-color:#ff235733}@supports (color:color-mix(in lab,red,red)){.border-rose-500\/20{border-color:color-mix(in oklab,var(--color-rose-500)20%,transparent)}}.border-rose-500\/30{border-color:#ff23574d}@supports (color:color-mix(in lab,red,red)){.border-rose-500\/30{border-color:color-mix(in oklab,var(--color-rose-500)30%,transparent)}}.border-rose-500\/50{border-color:#ff235780}@supports (color:color-mix(in lab,red,red)){.border-rose-500\/50{border-color:color-mix(in oklab,var(--color-rose-500)50%,transparent)}}.border-l-amber-500{border-left-color:var(--color-amber-500)}.border-l-blue-500{border-left-color:var(--color-blue-500)}.border-l-rose-500{border-left-color:var(--color-rose-500)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-500{background-color:var(--color-amber-500)}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/10{background-color:color-mix(in oklab,var(--color-amber-500)10%,transparent)}}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/15{background-color:color-mix(in oklab,var(--color-amber-500)15%,transparent)}}.bg-blue-400{background-color:var(--color-blue-400)}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/10{background-color:color-mix(in oklab,var(--color-blue-500)10%,transparent)}}.bg-blue-600{background-color:var(--color-blue-600)}.bg-blue-700{background-color:var(--color-blue-700)}.bg-cyan-500{background-color:var(--color-cyan-500)}.bg-cyan-500\/10{background-color:#00b7d71a}@supports (color:color-mix(in lab,red,red)){.bg-cyan-500\/10{background-color:color-mix(in oklab,var(--color-cyan-500)10%,transparent)}}.bg-cyan-500\/15{background-color:#00b7d726}@supports (color:color-mix(in lab,red,red)){.bg-cyan-500\/15{background-color:color-mix(in oklab,var(--color-cyan-500)15%,transparent)}}.bg-cyan-500\/60{background-color:#00b7d799}@supports (color:color-mix(in lab,red,red)){.bg-cyan-500\/60{background-color:color-mix(in oklab,var(--color-cyan-500)60%,transparent)}}.bg-emerald-400{background-color:var(--color-emerald-400)}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab,red,red)){.bg-emerald-500\/10{background-color:color-mix(in oklab,var(--color-emerald-500)10%,transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab,red,red)){.bg-emerald-500\/15{background-color:color-mix(in oklab,var(--color-emerald-500)15%,transparent)}}.bg-emerald-500\/20{background-color:#00bb7f33}@supports (color:color-mix(in lab,red,red)){.bg-emerald-500\/20{background-color:color-mix(in oklab,var(--color-emerald-500)20%,transparent)}}.bg-gray-400{background-color:var(--color-gray-400)}.bg-gray-500{background-color:var(--color-gray-500)}.bg-gray-500\/10{background-color:#6a72821a}@supports (color:color-mix(in lab,red,red)){.bg-gray-500\/10{background-color:color-mix(in oklab,var(--color-gray-500)10%,transparent)}}.bg-gray-600{background-color:var(--color-gray-600)}.bg-gray-700{background-color:var(--color-gray-700)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-gray-800\/20{background-color:#1e293933}@supports (color:color-mix(in lab,red,red)){.bg-gray-800\/20{background-color:color-mix(in oklab,var(--color-gray-800)20%,transparent)}}.bg-gray-800\/30{background-color:#1e29394d}@supports (color:color-mix(in lab,red,red)){.bg-gray-800\/30{background-color:color-mix(in oklab,var(--color-gray-800)30%,transparent)}}.bg-gray-800\/40{background-color:#1e293966}@supports (color:color-mix(in lab,red,red)){.bg-gray-800\/40{background-color:color-mix(in oklab,var(--color-gray-800)40%,transparent)}}.bg-gray-800\/50{background-color:#1e293980}@supports (color:color-mix(in lab,red,red)){.bg-gray-800\/50{background-color:color-mix(in oklab,var(--color-gray-800)50%,transparent)}}.bg-gray-900{background-color:var(--color-gray-900)}.bg-gray-900\/50{background-color:#10182880}@supports (color:color-mix(in lab,red,red)){.bg-gray-900\/50{background-color:color-mix(in oklab,var(--color-gray-900)50%,transparent)}}.bg-gray-950{background-color:var(--color-gray-950)}.bg-green-400{background-color:var(--color-green-400)}.bg-indigo-500{background-color:var(--color-indigo-500)}.bg-indigo-500\/10{background-color:#625fff1a}@supports (color:color-mix(in lab,red,red)){.bg-indigo-500\/10{background-color:color-mix(in oklab,var(--color-indigo-500)10%,transparent)}}.bg-indigo-500\/20{background-color:#625fff33}@supports (color:color-mix(in lab,red,red)){.bg-indigo-500\/20{background-color:color-mix(in oklab,var(--color-indigo-500)20%,transparent)}}.bg-indigo-500\/40{background-color:#625fff66}@supports (color:color-mix(in lab,red,red)){.bg-indigo-500\/40{background-color:color-mix(in oklab,var(--color-indigo-500)40%,transparent)}}.bg-indigo-500\/60{background-color:#625fff99}@supports (color:color-mix(in lab,red,red)){.bg-indigo-500\/60{background-color:color-mix(in oklab,var(--color-indigo-500)60%,transparent)}}.bg-indigo-600{background-color:var(--color-indigo-600)}.bg-red-400{background-color:var(--color-red-400)}.bg-rose-400{background-color:var(--color-rose-400)}.bg-rose-500{background-color:var(--color-rose-500)}.bg-rose-500\/10{background-color:#ff23571a}@supports (color:color-mix(in lab,red,red)){.bg-rose-500\/10{background-color:color-mix(in oklab,var(--color-rose-500)10%,transparent)}}.bg-rose-500\/15{background-color:#ff235726}@supports (color:color-mix(in lab,red,red)){.bg-rose-500\/15{background-color:color-mix(in oklab,var(--color-rose-500)15%,transparent)}}.bg-white{background-color:var(--color-white)}.bg-yellow-400{background-color:var(--color-yellow-400)}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-amber-500\/10{--tw-gradient-from:#f99c001a}@supports (color:color-mix(in lab,red,red)){.from-amber-500\/10{--tw-gradient-from:color-mix(in oklab,var(--color-amber-500)10%,transparent)}}.from-amber-500\/10{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-cyan-500\/10{--tw-gradient-from:#00b7d71a}@supports (color:color-mix(in lab,red,red)){.from-cyan-500\/10{--tw-gradient-from:color-mix(in oklab,var(--color-cyan-500)10%,transparent)}}.from-cyan-500\/10{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-emerald-500\/10{--tw-gradient-from:#00bb7f1a}@supports (color:color-mix(in lab,red,red)){.from-emerald-500\/10{--tw-gradient-from:color-mix(in oklab,var(--color-emerald-500)10%,transparent)}}.from-emerald-500\/10{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-indigo-500\/10{--tw-gradient-from:#625fff1a}@supports (color:color-mix(in lab,red,red)){.from-indigo-500\/10{--tw-gradient-from:color-mix(in oklab,var(--color-indigo-500)10%,transparent)}}.from-indigo-500\/10{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-rose-500\/10{--tw-gradient-from:#ff23571a}@supports (color:color-mix(in lab,red,red)){.from-rose-500\/10{--tw-gradient-from:color-mix(in oklab,var(--color-rose-500)10%,transparent)}}.from-rose-500\/10{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-amber-500\/5{--tw-gradient-to:#f99c000d}@supports (color:color-mix(in lab,red,red)){.to-amber-500\/5{--tw-gradient-to:color-mix(in oklab,var(--color-amber-500)5%,transparent)}}.to-amber-500\/5{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-cyan-500\/5{--tw-gradient-to:#00b7d70d}@supports (color:color-mix(in lab,red,red)){.to-cyan-500\/5{--tw-gradient-to:color-mix(in oklab,var(--color-cyan-500)5%,transparent)}}.to-cyan-500\/5{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-emerald-500\/5{--tw-gradient-to:#00bb7f0d}@supports (color:color-mix(in lab,red,red)){.to-emerald-500\/5{--tw-gradient-to:color-mix(in oklab,var(--color-emerald-500)5%,transparent)}}.to-emerald-500\/5{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-500\/5{--tw-gradient-to:#625fff0d}@supports (color:color-mix(in lab,red,red)){.to-indigo-500\/5{--tw-gradient-to:color-mix(in oklab,var(--color-indigo-500)5%,transparent)}}.to-indigo-500\/5{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-rose-500\/5{--tw-gradient-to:#ff23570d}@supports (color:color-mix(in lab,red,red)){.to-rose-500\/5{--tw-gradient-to:color-mix(in oklab,var(--color-rose-500)5%,transparent)}}.to-rose-500\/5{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-5{padding:calc(var(--spacing)*5)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-5{padding-block:calc(var(--spacing)*5)}.py-16{padding-block:calc(var(--spacing)*16)}.pt-4{padding-top:calc(var(--spacing)*4)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pl-4{padding-left:calc(var(--spacing)*4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-400{color:var(--color-amber-400)}.text-blue-400{color:var(--color-blue-400)}.text-cyan-400{color:var(--color-cyan-400)}.text-emerald-400{color:var(--color-emerald-400)}.text-emerald-500{color:var(--color-emerald-500)}.text-gray-100{color:var(--color-gray-100)}.text-gray-200{color:var(--color-gray-200)}.text-gray-300{color:var(--color-gray-300)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-indigo-400{color:var(--color-indigo-400)}.text-rose-300{color:var(--color-rose-300)}.text-rose-400{color:var(--color-rose-400)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-25{opacity:.25}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-amber-500\/50{--tw-ring-color:#f99c0080}@supports (color:color-mix(in lab,red,red)){.ring-amber-500\/50{--tw-ring-color:color-mix(in oklab,var(--color-amber-500)50%,transparent)}}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-500{--tw-duration:.5s;transition-duration:.5s}@media(hover:hover){.group-hover\:text-gray-400:is(:where(.group):hover *){color:var(--color-gray-400)}.group-hover\:text-white:is(:where(.group):hover *){color:var(--color-white)}.group-hover\/item\:opacity-100:is(:where(.group\/item):hover *){opacity:1}.hover\:border-amber-500\/40:hover{border-color:#f99c0066}@supports (color:color-mix(in lab,red,red)){.hover\:border-amber-500\/40:hover{border-color:color-mix(in oklab,var(--color-amber-500)40%,transparent)}}.hover\:border-gray-700:hover{border-color:var(--color-gray-700)}.hover\:border-indigo-500\/30:hover{border-color:#625fff4d}@supports (color:color-mix(in lab,red,red)){.hover\:border-indigo-500\/30:hover{border-color:color-mix(in oklab,var(--color-indigo-500)30%,transparent)}}.hover\:bg-gray-600:hover{background-color:var(--color-gray-600)}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:bg-gray-800:hover{background-color:var(--color-gray-800)}.hover\:bg-gray-800\/20:hover{background-color:#1e293933}@supports (color:color-mix(in lab,red,red)){.hover\:bg-gray-800\/20:hover{background-color:color-mix(in oklab,var(--color-gray-800)20%,transparent)}}.hover\:bg-gray-800\/30:hover{background-color:#1e29394d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-gray-800\/30:hover{background-color:color-mix(in oklab,var(--color-gray-800)30%,transparent)}}.hover\:bg-gray-800\/80:hover{background-color:#1e2939cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-gray-800\/80:hover{background-color:color-mix(in oklab,var(--color-gray-800)80%,transparent)}}.hover\:bg-indigo-500:hover{background-color:var(--color-indigo-500)}.hover\:bg-indigo-500\/60:hover{background-color:#625fff99}@supports (color:color-mix(in lab,red,red)){.hover\:bg-indigo-500\/60:hover{background-color:color-mix(in oklab,var(--color-indigo-500)60%,transparent)}}.hover\:text-amber-300:hover{color:var(--color-amber-300)}.hover\:text-emerald-300:hover{color:var(--color-emerald-300)}.hover\:text-gray-200:hover{color:var(--color-gray-200)}.hover\:text-gray-300:hover{color:var(--color-gray-300)}.hover\:text-indigo-300:hover{color:var(--color-indigo-300)}.hover\:text-rose-300:hover{color:var(--color-rose-300)}.hover\:text-rose-400:hover{color:var(--color-rose-400)}.hover\:text-white:hover{color:var(--color-white)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}}.focus\:border-indigo-500:focus{border-color:var(--color-indigo-500)}.focus\:ring-indigo-500:focus{--tw-ring-color:var(--color-indigo-500)}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:64rem){.lg\:col-span-2{grid-column:span 2/span 2}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:#374151;border-radius:3px}::-webkit-scrollbar-thumb:hover{background:#4b5563}@keyframes slideIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.animate-slide-in{animation:.2s ease-out slideIn}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.4}}.animate-pulse-dot{animation:2s ease-in-out infinite pulse-dot}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
|