prjct-cli 0.63.0 → 0.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -0
- package/core/__tests__/agentic/smart-context.test.ts +372 -0
- package/core/__tests__/ai-tools/formatters.test.ts +358 -0
- package/core/ai-tools/formatters.ts +76 -57
- package/core/ai-tools/registry.ts +2 -2
- package/core/services/sync-service.ts +6 -1
- package/core/types/agentic.ts +68 -5
- package/core/types/index.ts +7 -0
- package/core/types/memory.ts +12 -2
- package/dist/bin/prjct.mjs +80 -58
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,104 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.64.1] - 2026-02-05
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- generate IDE context files with correct paths and formats (PRJ-122) (#107)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [0.64.1] - 2026-02-05
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **IDE context file generation (PRJ-122)**: Fixed Cursor and Windsurf context file paths and formats
|
|
15
|
+
|
|
16
|
+
### Implementation Details
|
|
17
|
+
|
|
18
|
+
Fixed misalignment between `ai-provider.ts` (correct paths) and `ai-tools/registry.ts` (incorrect paths). Updated Cursor output to `.cursor/rules/prjct.mdc` with MDC format and `alwaysApply: true` frontmatter. Updated Windsurf output to `.windsurf/rules/prjct.md` with `trigger: always_on` frontmatter. Modified sync-service default behavior to auto-detect IDE tools when `.cursor/` or `.windsurf/` directories exist.
|
|
19
|
+
|
|
20
|
+
### Learnings
|
|
21
|
+
|
|
22
|
+
- Two separate implementations existed (ai-provider vs ai-tools) that needed synchronization
|
|
23
|
+
- IDE formats differ: Cursor uses `alwaysApply: true`, Windsurf uses `trigger: always_on`
|
|
24
|
+
- Auto-detection pattern: check for directory existence to enable optional features
|
|
25
|
+
|
|
26
|
+
### Test Plan
|
|
27
|
+
|
|
28
|
+
#### For QA
|
|
29
|
+
1. Run `prjct sync` in project with `.cursor/` dir - verify `.cursor/rules/prjct.mdc` generated
|
|
30
|
+
2. Run `prjct sync` in project with `.windsurf/` dir - verify `.windsurf/rules/prjct.md` generated
|
|
31
|
+
3. Verify Cursor file has `alwaysApply: true` in frontmatter
|
|
32
|
+
4. Verify Windsurf file has `trigger: always_on` in frontmatter
|
|
33
|
+
5. Run `bun test` - all 405 tests pass
|
|
34
|
+
|
|
35
|
+
#### For Users
|
|
36
|
+
- `prjct sync` now auto-generates IDE context files when `.cursor/` or `.windsurf/` directories exist
|
|
37
|
+
- No manual flags needed - detection is automatic
|
|
38
|
+
- No breaking changes
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## [0.64.0] - 2026-02-05
|
|
42
|
+
|
|
43
|
+
### Features
|
|
44
|
+
|
|
45
|
+
- add input source tagging for context items (PRJ-102) (#106)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## [0.63.2] - 2026-02-05
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- **Input source tagging (PRJ-102)**: Context items now support origin tracking via `_source` metadata
|
|
53
|
+
|
|
54
|
+
### Implementation Details
|
|
55
|
+
|
|
56
|
+
Added `InputSource` type with 10 standardized source categories (user_explicit, user_file, system_detected, system_generated, system_inferred, learned, external, inherited, cached, unknown). Created `SourceMetadata` interface with capturedAt timestamp and optional confidence/sourcePath fields. Added `SourcedItem` base interface and `createSourceMetadata()` helper function. Extended key context interfaces (AgentInfo, FeatureInfo, PatternInfo, GatheredInfo, LoadedAgent) to support source tracking. Updated MemoryMetadata with inputSource field for consistency.
|
|
57
|
+
|
|
58
|
+
### Learnings
|
|
59
|
+
|
|
60
|
+
- Anthropic pattern: always track origin of all data for traceability and debugging
|
|
61
|
+
- Using optional `_source` field allows backward-compatible adoption
|
|
62
|
+
|
|
63
|
+
### Test Plan
|
|
64
|
+
|
|
65
|
+
#### For QA
|
|
66
|
+
1. Run `bun run typecheck` - passes with new types
|
|
67
|
+
2. Run `bun test` - all 368 tests pass
|
|
68
|
+
3. Verify `InputSource` type is exported from `core/types`
|
|
69
|
+
|
|
70
|
+
#### For Users
|
|
71
|
+
- Context items now support source tracking via `_source` metadata
|
|
72
|
+
- Use `createSourceMetadata()` when creating context items
|
|
73
|
+
- No breaking changes
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## [0.63.1] - 2026-02-05
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
|
|
80
|
+
- **Unit tests for smart-context.ts (PRJ-84)**: 57 tests covering domain detection, file filtering, and type mappings
|
|
81
|
+
|
|
82
|
+
### Implementation Details
|
|
83
|
+
|
|
84
|
+
Created comprehensive test suite for SmartContext class: `detectDomain()` tests for all 6 domains (frontend, backend, devops, docs, testing, general), `filterFiles()` tests for file pattern matching, `estimateSize()` tests for token estimation, and type mapping function tests.
|
|
85
|
+
|
|
86
|
+
### Learnings
|
|
87
|
+
|
|
88
|
+
- Keyword detection uses substring matching - "be" in "better" matches backend keyword
|
|
89
|
+
- Frontend file pattern `/\.(tsx?|jsx?)$/` also matches plain `.ts` files (known behavior)
|
|
90
|
+
- Confidence scoring caps at 0.95 regardless of keyword count
|
|
91
|
+
|
|
92
|
+
### Test Plan
|
|
93
|
+
|
|
94
|
+
#### For QA
|
|
95
|
+
1. Run `bun test core/__tests__/agentic/smart-context.test.ts` - all 57 tests pass
|
|
96
|
+
2. Run `bun test` - full suite passes (368 tests)
|
|
97
|
+
|
|
98
|
+
#### For Users
|
|
99
|
+
- No user-facing changes (test coverage improvement)
|
|
100
|
+
|
|
101
|
+
|
|
3
102
|
## [0.63.0] - 2026-02-05
|
|
4
103
|
|
|
5
104
|
### Features
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Context Tests
|
|
3
|
+
* PRJ-84: Unit tests for smart-context.ts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from 'bun:test'
|
|
7
|
+
import smartContext, { SmartContext } from '../../agentic/smart-context'
|
|
8
|
+
import type { ContextDomain, TaskType } from '../../types'
|
|
9
|
+
|
|
10
|
+
describe('SmartContext PRJ-84', () => {
|
|
11
|
+
describe('detectDomain', () => {
|
|
12
|
+
describe('frontend detection', () => {
|
|
13
|
+
it('should detect frontend from UI keywords', () => {
|
|
14
|
+
const result = smartContext.detectDomain('Add a new button component')
|
|
15
|
+
expect(result.primary).toBe('frontend')
|
|
16
|
+
expect(result.confidence).toBeGreaterThan(0.5)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should detect frontend from React keywords', () => {
|
|
20
|
+
const result = smartContext.detectDomain('Create React component for user profile')
|
|
21
|
+
expect(result.primary).toBe('frontend')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should detect frontend from styling keywords', () => {
|
|
25
|
+
const result = smartContext.detectDomain('Fix CSS layout for responsive design')
|
|
26
|
+
expect(result.primary).toBe('frontend')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should detect frontend from TSX/JSX keywords', () => {
|
|
30
|
+
const result = smartContext.detectDomain('Update tsx file for modal animation')
|
|
31
|
+
expect(result.primary).toBe('frontend')
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('backend detection', () => {
|
|
36
|
+
it('should detect backend from API keywords', () => {
|
|
37
|
+
const result = smartContext.detectDomain('Create new API endpoint for users')
|
|
38
|
+
expect(result.primary).toBe('backend')
|
|
39
|
+
expect(result.confidence).toBeGreaterThan(0.5)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should detect backend from database keywords', () => {
|
|
43
|
+
const result = smartContext.detectDomain('Add database query for orders')
|
|
44
|
+
expect(result.primary).toBe('backend')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should detect backend from service keywords', () => {
|
|
48
|
+
const result = smartContext.detectDomain('Implement auth service handler')
|
|
49
|
+
expect(result.primary).toBe('backend')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should detect backend from GraphQL keywords', () => {
|
|
53
|
+
const result = smartContext.detectDomain('Add GraphQL resolver for products')
|
|
54
|
+
expect(result.primary).toBe('backend')
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('devops detection', () => {
|
|
59
|
+
it('should detect devops from Docker keywords', () => {
|
|
60
|
+
const result = smartContext.detectDomain('Create Docker container for deployment')
|
|
61
|
+
expect(result.primary).toBe('devops')
|
|
62
|
+
expect(result.confidence).toBeGreaterThan(0.5)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should detect devops from Kubernetes keywords', () => {
|
|
66
|
+
const result = smartContext.detectDomain('Update k8s deployment configuration')
|
|
67
|
+
expect(result.primary).toBe('devops')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should detect devops from CI/CD keywords', () => {
|
|
71
|
+
const result = smartContext.detectDomain('Fix CI pipeline for build process')
|
|
72
|
+
expect(result.primary).toBe('devops')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should detect devops from infrastructure keywords', () => {
|
|
76
|
+
const result = smartContext.detectDomain('Configure AWS infrastructure with terraform')
|
|
77
|
+
expect(result.primary).toBe('devops')
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
describe('docs detection', () => {
|
|
82
|
+
it('should detect docs from documentation keywords', () => {
|
|
83
|
+
// Note: "documentation" alone triggers docs domain
|
|
84
|
+
const result = smartContext.detectDomain('Update documentation for users')
|
|
85
|
+
expect(result.primary).toBe('docs')
|
|
86
|
+
expect(result.confidence).toBeGreaterThan(0.5)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should detect docs from README keywords', () => {
|
|
90
|
+
const result = smartContext.detectDomain('Add readme section for installation')
|
|
91
|
+
expect(result.primary).toBe('docs')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('should detect docs from changelog keywords', () => {
|
|
95
|
+
const result = smartContext.detectDomain('Update changelog for new release')
|
|
96
|
+
expect(result.primary).toBe('docs')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should detect docs from jsdoc keywords', () => {
|
|
100
|
+
const result = smartContext.detectDomain('Add jsdoc comments to functions')
|
|
101
|
+
expect(result.primary).toBe('docs')
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
describe('testing detection', () => {
|
|
106
|
+
it('should detect testing from test keywords', () => {
|
|
107
|
+
const result = smartContext.detectDomain('Add unit test for user service')
|
|
108
|
+
expect(result.primary).toBe('testing')
|
|
109
|
+
expect(result.confidence).toBeGreaterThan(0.5)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('should detect testing from Jest keywords', () => {
|
|
113
|
+
const result = smartContext.detectDomain('Write jest spec for validation')
|
|
114
|
+
expect(result.primary).toBe('testing')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('should detect testing from e2e keywords', () => {
|
|
118
|
+
const result = smartContext.detectDomain('Add e2e integration tests')
|
|
119
|
+
expect(result.primary).toBe('testing')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should detect testing from coverage keywords', () => {
|
|
123
|
+
const result = smartContext.detectDomain('Improve test coverage for auth module')
|
|
124
|
+
expect(result.primary).toBe('testing')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('should detect testing from mock/fixture keywords', () => {
|
|
128
|
+
const result = smartContext.detectDomain('Create mock fixtures for API tests')
|
|
129
|
+
expect(result.primary).toBe('testing')
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
describe('general/fallback detection', () => {
|
|
134
|
+
it('should return general for ambiguous tasks', () => {
|
|
135
|
+
const result = smartContext.detectDomain('Refactor code')
|
|
136
|
+
expect(result.primary).toBe('general')
|
|
137
|
+
expect(result.confidence).toBe(0.5)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('should return general for empty descriptions', () => {
|
|
141
|
+
const result = smartContext.detectDomain('')
|
|
142
|
+
expect(result.primary).toBe('general')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('should return general for non-technical descriptions', () => {
|
|
146
|
+
// Note: "be" in "better" matches backend keyword, so use different text
|
|
147
|
+
const result = smartContext.detectDomain('Improve this somehow')
|
|
148
|
+
expect(result.primary).toBe('general')
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe('secondary domains', () => {
|
|
153
|
+
it('should detect secondary domains for mixed tasks', () => {
|
|
154
|
+
const result = smartContext.detectDomain('Add API endpoint with React frontend component')
|
|
155
|
+
expect(result.primary).toBeDefined()
|
|
156
|
+
expect(result.secondary.length).toBeGreaterThan(0)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('should limit secondary domains to max 2', () => {
|
|
160
|
+
const result = smartContext.detectDomain(
|
|
161
|
+
'Add API endpoint with React component and Docker deploy with test coverage'
|
|
162
|
+
)
|
|
163
|
+
expect(result.secondary.length).toBeLessThanOrEqual(2)
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
describe('confidence scoring', () => {
|
|
168
|
+
it('should have higher confidence for strong domain signals', () => {
|
|
169
|
+
const strong = smartContext.detectDomain('Create React component with jsx tsx ui')
|
|
170
|
+
const weak = smartContext.detectDomain('Fix bug in component')
|
|
171
|
+
// Strong has multiple matching keywords, weak has fewer
|
|
172
|
+
expect(strong.confidence).toBeGreaterThanOrEqual(weak.confidence)
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('should cap confidence at 0.95', () => {
|
|
176
|
+
const result = smartContext.detectDomain(
|
|
177
|
+
'ui component react vue angular css style button form modal layout responsive animation dom html frontend jsx tsx'
|
|
178
|
+
)
|
|
179
|
+
expect(result.confidence).toBeLessThanOrEqual(0.95)
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
describe('filterFiles', () => {
|
|
185
|
+
const testFiles = [
|
|
186
|
+
'src/components/Button.tsx',
|
|
187
|
+
'src/components/Modal.jsx',
|
|
188
|
+
'src/api/users.ts',
|
|
189
|
+
'src/services/auth.ts',
|
|
190
|
+
'src/models/User.ts',
|
|
191
|
+
'docker/Dockerfile',
|
|
192
|
+
'.github/workflows/ci.yml',
|
|
193
|
+
'deploy/k8s/deployment.yaml',
|
|
194
|
+
'docs/README.md',
|
|
195
|
+
'docs/api.md',
|
|
196
|
+
'tests/unit/auth.test.ts',
|
|
197
|
+
'__tests__/components/Button.test.tsx',
|
|
198
|
+
'package.json',
|
|
199
|
+
'tsconfig.json',
|
|
200
|
+
'vite.config.ts',
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
// Access private method via class instance
|
|
204
|
+
const smartContextInstance = new SmartContext()
|
|
205
|
+
const filterFiles = (files: string[], domain: ContextDomain) => {
|
|
206
|
+
// @ts-expect-error - accessing private method for testing
|
|
207
|
+
return smartContextInstance.filterFiles(files, domain)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
describe('frontend filtering', () => {
|
|
211
|
+
it('should include component files', () => {
|
|
212
|
+
const result = filterFiles(testFiles, 'frontend')
|
|
213
|
+
expect(result).toContain('src/components/Button.tsx')
|
|
214
|
+
expect(result).toContain('src/components/Modal.jsx')
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('should include config files', () => {
|
|
218
|
+
const result = filterFiles(testFiles, 'frontend')
|
|
219
|
+
expect(result).toContain('package.json')
|
|
220
|
+
expect(result).toContain('tsconfig.json')
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
it('should exclude non-code files', () => {
|
|
224
|
+
const result = filterFiles(testFiles, 'frontend')
|
|
225
|
+
// Note: .ts files match frontend pattern /\.(tsx?|jsx?)$/ because tsx? = ts or tsx
|
|
226
|
+
// So backend .ts files are included - this is a known quirk
|
|
227
|
+
expect(result).not.toContain('docker/Dockerfile')
|
|
228
|
+
expect(result).not.toContain('docs/README.md')
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
describe('backend filtering', () => {
|
|
233
|
+
it('should include API and service files', () => {
|
|
234
|
+
const result = filterFiles(testFiles, 'backend')
|
|
235
|
+
expect(result).toContain('src/api/users.ts')
|
|
236
|
+
expect(result).toContain('src/services/auth.ts')
|
|
237
|
+
expect(result).toContain('src/models/User.ts')
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('should include config files', () => {
|
|
241
|
+
const result = filterFiles(testFiles, 'backend')
|
|
242
|
+
expect(result).toContain('package.json')
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
describe('devops filtering', () => {
|
|
247
|
+
it('should include Docker and CI files', () => {
|
|
248
|
+
const result = filterFiles(testFiles, 'devops')
|
|
249
|
+
expect(result).toContain('docker/Dockerfile')
|
|
250
|
+
expect(result).toContain('.github/workflows/ci.yml')
|
|
251
|
+
expect(result).toContain('deploy/k8s/deployment.yaml')
|
|
252
|
+
})
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
describe('docs filtering', () => {
|
|
256
|
+
it('should include markdown files', () => {
|
|
257
|
+
const result = filterFiles(testFiles, 'docs')
|
|
258
|
+
expect(result).toContain('docs/README.md')
|
|
259
|
+
expect(result).toContain('docs/api.md')
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
describe('testing filtering', () => {
|
|
264
|
+
it('should include test files', () => {
|
|
265
|
+
const result = filterFiles(testFiles, 'testing')
|
|
266
|
+
expect(result).toContain('tests/unit/auth.test.ts')
|
|
267
|
+
expect(result).toContain('__tests__/components/Button.test.tsx')
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
describe('general filtering', () => {
|
|
272
|
+
it('should return all files for general domain', () => {
|
|
273
|
+
const result = filterFiles(testFiles, 'general')
|
|
274
|
+
expect(result).toEqual(testFiles)
|
|
275
|
+
})
|
|
276
|
+
})
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
describe('estimateSize', () => {
|
|
280
|
+
// @ts-expect-error - accessing private method for testing
|
|
281
|
+
const estimateSize = smartContext.estimateSize.bind(smartContext)
|
|
282
|
+
|
|
283
|
+
it('should return minimum 100 for empty context', () => {
|
|
284
|
+
const result = estimateSize({})
|
|
285
|
+
expect(result).toBe(100)
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
it('should estimate agents at ~50 tokens each', () => {
|
|
289
|
+
const result = estimateSize({ agents: [{}, {}, {}] })
|
|
290
|
+
expect(result).toBe(150) // 3 * 50
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('should estimate roadmap items at ~50 tokens each', () => {
|
|
294
|
+
const result = estimateSize({ roadmap: [{}, {}] })
|
|
295
|
+
expect(result).toBe(100) // 2 * 50
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
it('should estimate patterns at ~30 tokens each', () => {
|
|
299
|
+
const result = estimateSize({ patterns: [{}, {}, {}, {}] })
|
|
300
|
+
expect(result).toBe(120) // 4 * 30
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it('should estimate stack at 100 tokens', () => {
|
|
304
|
+
const result = estimateSize({ stack: {} })
|
|
305
|
+
expect(result).toBe(100)
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
it('should estimate files at ~10 tokens each', () => {
|
|
309
|
+
const result = estimateSize({ files: ['a', 'b', 'c', 'd', 'e'] })
|
|
310
|
+
expect(result).toBe(100) // 5 * 10 = 50, min 100
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
it('should estimate state at 200 tokens', () => {
|
|
314
|
+
const result = estimateSize({ state: {} })
|
|
315
|
+
expect(result).toBe(200)
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it('should combine all estimates', () => {
|
|
319
|
+
const result = estimateSize({
|
|
320
|
+
agents: [{}, {}], // 100
|
|
321
|
+
roadmap: [{}], // 50
|
|
322
|
+
patterns: [{}], // 30
|
|
323
|
+
stack: {}, // 100
|
|
324
|
+
files: ['a'], // 10
|
|
325
|
+
state: {}, // 200
|
|
326
|
+
})
|
|
327
|
+
expect(result).toBe(490)
|
|
328
|
+
})
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
describe('taskTypeToContextDomain', () => {
|
|
332
|
+
const testCases: Array<{ input: TaskType; expected: ContextDomain }> = [
|
|
333
|
+
{ input: 'frontend', expected: 'frontend' },
|
|
334
|
+
{ input: 'backend', expected: 'backend' },
|
|
335
|
+
{ input: 'devops', expected: 'devops' },
|
|
336
|
+
{ input: 'database', expected: 'backend' },
|
|
337
|
+
{ input: 'testing', expected: 'testing' },
|
|
338
|
+
{ input: 'documentation', expected: 'docs' },
|
|
339
|
+
{ input: 'refactoring', expected: 'general' },
|
|
340
|
+
{ input: 'bugfix', expected: 'general' },
|
|
341
|
+
{ input: 'feature', expected: 'general' },
|
|
342
|
+
{ input: 'design', expected: 'frontend' },
|
|
343
|
+
{ input: 'other', expected: 'general' },
|
|
344
|
+
]
|
|
345
|
+
|
|
346
|
+
for (const { input, expected } of testCases) {
|
|
347
|
+
it(`should map ${input} to ${expected}`, () => {
|
|
348
|
+
expect(smartContext.taskTypeToContextDomain(input)).toBe(expected)
|
|
349
|
+
})
|
|
350
|
+
}
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
describe('contextDomainToTaskType (via getRecommendedContext)', () => {
|
|
354
|
+
// Test the private method indirectly through detectDomain verification
|
|
355
|
+
it('should have consistent bidirectional mapping for core domains', () => {
|
|
356
|
+
// Frontend maps to frontend
|
|
357
|
+
const frontendResult = smartContext.detectDomain('Create React component')
|
|
358
|
+
expect(frontendResult.primary).toBe('frontend')
|
|
359
|
+
expect(smartContext.taskTypeToContextDomain('frontend')).toBe('frontend')
|
|
360
|
+
|
|
361
|
+
// Backend maps to backend
|
|
362
|
+
const backendResult = smartContext.detectDomain('Add API endpoint')
|
|
363
|
+
expect(backendResult.primary).toBe('backend')
|
|
364
|
+
expect(smartContext.taskTypeToContextDomain('backend')).toBe('backend')
|
|
365
|
+
|
|
366
|
+
// Testing maps to testing
|
|
367
|
+
const testingResult = smartContext.detectDomain('Add unit test')
|
|
368
|
+
expect(testingResult.primary).toBe('testing')
|
|
369
|
+
expect(smartContext.taskTypeToContextDomain('testing')).toBe('testing')
|
|
370
|
+
})
|
|
371
|
+
})
|
|
372
|
+
})
|