oh-my-claude-sisyphus 3.7.16 → 3.8.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +8 -6
- package/agents/AGENTS.md +8 -8
- package/agents/architect.md +32 -0
- package/agents/build-fixer.md +35 -0
- package/agents/code-reviewer.md +51 -0
- package/agents/executor-high.md +49 -0
- package/agents/explore-high.md +39 -0
- package/agents/explore-medium.md +33 -0
- package/dist/__tests__/hooks/learner/bridge.test.js +13 -7
- package/dist/__tests__/hooks/learner/bridge.test.js.map +1 -1
- package/dist/__tests__/hooks.test.js +306 -67
- package/dist/__tests__/hooks.test.js.map +1 -1
- package/dist/__tests__/installer.test.js +31 -15
- package/dist/__tests__/installer.test.js.map +1 -1
- package/dist/hooks/bridge.js +3 -3
- package/dist/hooks/bridge.js.map +1 -1
- package/dist/hooks/clear-suggestions/constants.d.ts +54 -0
- package/dist/hooks/clear-suggestions/constants.d.ts.map +1 -0
- package/dist/hooks/clear-suggestions/constants.js +102 -0
- package/dist/hooks/clear-suggestions/constants.js.map +1 -0
- package/dist/hooks/clear-suggestions/index.d.ts +61 -0
- package/dist/hooks/clear-suggestions/index.d.ts.map +1 -0
- package/dist/hooks/clear-suggestions/index.js +276 -0
- package/dist/hooks/clear-suggestions/index.js.map +1 -0
- package/dist/hooks/clear-suggestions/triggers.d.ts +65 -0
- package/dist/hooks/clear-suggestions/triggers.d.ts.map +1 -0
- package/dist/hooks/clear-suggestions/triggers.js +222 -0
- package/dist/hooks/clear-suggestions/triggers.js.map +1 -0
- package/dist/hooks/clear-suggestions/types.d.ts +92 -0
- package/dist/hooks/clear-suggestions/types.d.ts.map +1 -0
- package/dist/hooks/clear-suggestions/types.js +9 -0
- package/dist/hooks/clear-suggestions/types.js.map +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/keyword-detector/__tests__/index.test.js +51 -51
- package/dist/hooks/keyword-detector/__tests__/index.test.js.map +1 -1
- package/dist/hooks/keyword-detector/index.d.ts +1 -1
- package/dist/hooks/keyword-detector/index.d.ts.map +1 -1
- package/dist/hooks/keyword-detector/index.js +18 -5
- package/dist/hooks/keyword-detector/index.js.map +1 -1
- package/docs/CLAUDE.md +83 -0
- package/package.json +1 -1
- package/scripts/keyword-detector.mjs +203 -83
- package/scripts/post-tool-verifier.mjs +39 -1
- package/templates/hooks/keyword-detector.sh +197 -31
|
@@ -108,53 +108,33 @@ describe('Keyword Detector', () => {
|
|
|
108
108
|
expect(detected[0].keyword).toBe('ultrathink');
|
|
109
109
|
});
|
|
110
110
|
it('should detect think keyword', () => {
|
|
111
|
-
const detected = detectKeywordsWithType('Let me think about it');
|
|
111
|
+
const detected = detectKeywordsWithType('Let me think hard about it');
|
|
112
112
|
expect(detected).toHaveLength(1);
|
|
113
113
|
expect(detected[0].type).toBe('ultrathink');
|
|
114
|
-
expect(detected[0].keyword).toBe('think');
|
|
114
|
+
expect(detected[0].keyword).toBe('think hard');
|
|
115
115
|
});
|
|
116
|
-
it('should detect
|
|
117
|
-
const searchTerms = ['search', 'find', 'locate', 'lookup', 'explore'];
|
|
118
|
-
for (const term of searchTerms) {
|
|
119
|
-
const detected = detectKeywordsWithType(`Please ${term} this file`);
|
|
120
|
-
expect(detected).toHaveLength(1);
|
|
121
|
-
expect(detected[0].type).toBe('search');
|
|
122
|
-
expect(detected[0].keyword).toBe(term);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
it('should detect search patterns', () => {
|
|
116
|
+
it('should detect deepsearch keywords for codebase search', () => {
|
|
126
117
|
const patterns = [
|
|
127
|
-
'
|
|
128
|
-
'
|
|
129
|
-
'
|
|
118
|
+
'search the codebase',
|
|
119
|
+
'find in codebase',
|
|
120
|
+
'search code for pattern'
|
|
130
121
|
];
|
|
131
122
|
for (const pattern of patterns) {
|
|
132
123
|
const detected = detectKeywordsWithType(pattern);
|
|
133
124
|
expect(detected.length).toBeGreaterThan(0);
|
|
134
|
-
|
|
135
|
-
expect(hasSearchType).toBe(true);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
it('should detect analyze keywords', () => {
|
|
139
|
-
const analyzeTerms = ['analyze', 'investigate', 'examine', 'debug'];
|
|
140
|
-
for (const term of analyzeTerms) {
|
|
141
|
-
const detected = detectKeywordsWithType(`Please ${term} this code`);
|
|
142
|
-
expect(detected).toHaveLength(1);
|
|
143
|
-
expect(detected[0].type).toBe('analyze');
|
|
144
|
-
expect(detected[0].keyword).toBe(term);
|
|
125
|
+
expect(detected[0].type).toBe('deepsearch');
|
|
145
126
|
}
|
|
146
127
|
});
|
|
147
|
-
it('should detect analyze patterns', () => {
|
|
128
|
+
it('should detect analyze keywords with restricted patterns', () => {
|
|
148
129
|
const patterns = [
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'
|
|
130
|
+
'deep analyze this code',
|
|
131
|
+
'investigate the bug',
|
|
132
|
+
'debug the issue'
|
|
152
133
|
];
|
|
153
134
|
for (const pattern of patterns) {
|
|
154
135
|
const detected = detectKeywordsWithType(pattern);
|
|
155
136
|
expect(detected.length).toBeGreaterThan(0);
|
|
156
|
-
|
|
157
|
-
expect(hasAnalyzeType).toBe(true);
|
|
137
|
+
expect(detected[0].type).toBe('analyze');
|
|
158
138
|
}
|
|
159
139
|
});
|
|
160
140
|
it('should be case insensitive', () => {
|
|
@@ -173,27 +153,215 @@ describe('Keyword Detector', () => {
|
|
|
173
153
|
expect(detected[0].keyword).toBe('ultrawork');
|
|
174
154
|
});
|
|
175
155
|
it('should include position information', () => {
|
|
176
|
-
const detected = detectKeywordsWithType('Start search here');
|
|
177
|
-
expect(detected[0].position).
|
|
156
|
+
const detected = detectKeywordsWithType('Start search the codebase here');
|
|
157
|
+
expect(detected[0].position).toBeGreaterThanOrEqual(0);
|
|
178
158
|
});
|
|
179
159
|
it('should return empty array for no matches', () => {
|
|
180
160
|
const detected = detectKeywordsWithType('Just plain text');
|
|
181
161
|
expect(detected).toEqual([]);
|
|
182
162
|
});
|
|
183
163
|
it('should detect multiple different keyword types', () => {
|
|
184
|
-
const text = 'search and
|
|
164
|
+
const text = 'search the codebase and investigate the bug';
|
|
185
165
|
const detected = detectKeywordsWithType(text);
|
|
186
166
|
expect(detected.length).toBeGreaterThanOrEqual(2);
|
|
187
167
|
const types = detected.map(d => d.type);
|
|
188
|
-
expect(types).toContain('
|
|
168
|
+
expect(types).toContain('deepsearch');
|
|
189
169
|
expect(types).toContain('analyze');
|
|
190
170
|
});
|
|
171
|
+
// New keyword types tests
|
|
172
|
+
it('should detect cancel keyword', () => {
|
|
173
|
+
const detected = detectKeywordsWithType('stop this task');
|
|
174
|
+
expect(detected).toHaveLength(1);
|
|
175
|
+
expect(detected[0].type).toBe('cancel');
|
|
176
|
+
expect(detected[0].keyword).toBe('stop');
|
|
177
|
+
});
|
|
178
|
+
it('should detect cancel keyword variations', () => {
|
|
179
|
+
const cancelTerms = ['stop', 'cancel', 'abort'];
|
|
180
|
+
for (const term of cancelTerms) {
|
|
181
|
+
const detected = detectKeywordsWithType(`Please ${term} the process`);
|
|
182
|
+
expect(detected).toHaveLength(1);
|
|
183
|
+
expect(detected[0].type).toBe('cancel');
|
|
184
|
+
expect(detected[0].keyword).toBe(term);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
it('should detect ultrapilot keyword', () => {
|
|
188
|
+
const detected = detectKeywordsWithType('use ultrapilot for this');
|
|
189
|
+
expect(detected).toHaveLength(1);
|
|
190
|
+
expect(detected[0].type).toBe('ultrapilot');
|
|
191
|
+
expect(detected[0].keyword).toBe('ultrapilot');
|
|
192
|
+
});
|
|
193
|
+
it('should detect ultrapilot patterns', () => {
|
|
194
|
+
const patterns = [
|
|
195
|
+
'ultrapilot this project',
|
|
196
|
+
'parallel build the app',
|
|
197
|
+
'swarm build the system'
|
|
198
|
+
];
|
|
199
|
+
for (const pattern of patterns) {
|
|
200
|
+
const detected = detectKeywordsWithType(pattern);
|
|
201
|
+
expect(detected.length).toBeGreaterThan(0);
|
|
202
|
+
const hasUltrapilot = detected.some(d => d.type === 'ultrapilot');
|
|
203
|
+
expect(hasUltrapilot).toBe(true);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
it('should detect ecomode keyword', () => {
|
|
207
|
+
const detected = detectKeywordsWithType('use ecomode for this');
|
|
208
|
+
expect(detected).toHaveLength(1);
|
|
209
|
+
expect(detected[0].type).toBe('ecomode');
|
|
210
|
+
expect(detected[0].keyword).toBe('ecomode');
|
|
211
|
+
});
|
|
212
|
+
it('should detect ecomode variations', () => {
|
|
213
|
+
const ecoTerms = ['eco', 'ecomode', 'efficient', 'save-tokens', 'budget'];
|
|
214
|
+
for (const term of ecoTerms) {
|
|
215
|
+
const detected = detectKeywordsWithType(`Use ${term} mode`);
|
|
216
|
+
expect(detected).toHaveLength(1);
|
|
217
|
+
expect(detected[0].type).toBe('ecomode');
|
|
218
|
+
expect(detected[0].keyword).toBe(term);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
it('should detect swarm keyword', () => {
|
|
222
|
+
const detected = detectKeywordsWithType('swarm 5 agents to fix this');
|
|
223
|
+
expect(detected).toHaveLength(1);
|
|
224
|
+
expect(detected[0].type).toBe('swarm');
|
|
225
|
+
expect(detected[0].keyword).toBe('swarm 5 agents');
|
|
226
|
+
});
|
|
227
|
+
it('should detect coordinated agents pattern', () => {
|
|
228
|
+
const detected = detectKeywordsWithType('use coordinated agents');
|
|
229
|
+
expect(detected).toHaveLength(1);
|
|
230
|
+
expect(detected[0].type).toBe('swarm');
|
|
231
|
+
expect(detected[0].keyword).toBe('coordinated agents');
|
|
232
|
+
});
|
|
233
|
+
it('should detect pipeline keyword', () => {
|
|
234
|
+
const detected = detectKeywordsWithType('pipeline this task');
|
|
235
|
+
expect(detected).toHaveLength(1);
|
|
236
|
+
expect(detected[0].type).toBe('pipeline');
|
|
237
|
+
expect(detected[0].keyword).toBe('pipeline');
|
|
238
|
+
});
|
|
239
|
+
it('should detect chain agents pattern', () => {
|
|
240
|
+
const detected = detectKeywordsWithType('chain agents together');
|
|
241
|
+
expect(detected).toHaveLength(1);
|
|
242
|
+
expect(detected[0].type).toBe('pipeline');
|
|
243
|
+
expect(detected[0].keyword).toBe('chain agents');
|
|
244
|
+
});
|
|
245
|
+
it('should detect ralplan keyword', () => {
|
|
246
|
+
const detected = detectKeywordsWithType('ralplan this feature');
|
|
247
|
+
expect(detected).toHaveLength(1);
|
|
248
|
+
expect(detected[0].type).toBe('ralplan');
|
|
249
|
+
expect(detected[0].keyword).toBe('ralplan');
|
|
250
|
+
});
|
|
251
|
+
it('should detect plan patterns', () => {
|
|
252
|
+
const patterns = [
|
|
253
|
+
'plan this feature',
|
|
254
|
+
'plan the refactoring'
|
|
255
|
+
];
|
|
256
|
+
for (const pattern of patterns) {
|
|
257
|
+
const detected = detectKeywordsWithType(pattern);
|
|
258
|
+
expect(detected.length).toBeGreaterThan(0);
|
|
259
|
+
const hasPlan = detected.some(d => d.type === 'plan');
|
|
260
|
+
expect(hasPlan).toBe(true);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
it('should detect tdd keyword', () => {
|
|
264
|
+
const detected = detectKeywordsWithType('use tdd for this');
|
|
265
|
+
expect(detected).toHaveLength(1);
|
|
266
|
+
expect(detected[0].type).toBe('tdd');
|
|
267
|
+
expect(detected[0].keyword).toBe('tdd');
|
|
268
|
+
});
|
|
269
|
+
it('should detect tdd patterns', () => {
|
|
270
|
+
const patterns = [
|
|
271
|
+
'test first development',
|
|
272
|
+
'red green refactor'
|
|
273
|
+
];
|
|
274
|
+
for (const pattern of patterns) {
|
|
275
|
+
const detected = detectKeywordsWithType(pattern);
|
|
276
|
+
expect(detected.length).toBeGreaterThan(0);
|
|
277
|
+
const hasTDD = detected.some(d => d.type === 'tdd');
|
|
278
|
+
expect(hasTDD).toBe(true);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
it('should detect research keyword', () => {
|
|
282
|
+
const detected = detectKeywordsWithType('research this topic');
|
|
283
|
+
expect(detected).toHaveLength(1);
|
|
284
|
+
expect(detected[0].type).toBe('research');
|
|
285
|
+
expect(detected[0].keyword).toBe('research');
|
|
286
|
+
});
|
|
287
|
+
it('should detect research patterns', () => {
|
|
288
|
+
const patterns = [
|
|
289
|
+
'analyze data from the file',
|
|
290
|
+
'run statistics on this'
|
|
291
|
+
];
|
|
292
|
+
for (const pattern of patterns) {
|
|
293
|
+
const detected = detectKeywordsWithType(pattern);
|
|
294
|
+
expect(detected.length).toBeGreaterThan(0);
|
|
295
|
+
const hasResearch = detected.some(d => d.type === 'research');
|
|
296
|
+
expect(hasResearch).toBe(true);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
it('should detect deepsearch keyword', () => {
|
|
300
|
+
const detected = detectKeywordsWithType('deepsearch for the pattern');
|
|
301
|
+
expect(detected).toHaveLength(1);
|
|
302
|
+
expect(detected[0].type).toBe('deepsearch');
|
|
303
|
+
expect(detected[0].keyword).toBe('deepsearch');
|
|
304
|
+
});
|
|
305
|
+
it('should detect deepsearch patterns', () => {
|
|
306
|
+
const patterns = [
|
|
307
|
+
'search the codebase for errors',
|
|
308
|
+
'search codebase for pattern',
|
|
309
|
+
'find in codebase',
|
|
310
|
+
'find in all files'
|
|
311
|
+
];
|
|
312
|
+
for (const pattern of patterns) {
|
|
313
|
+
const detected = detectKeywordsWithType(pattern);
|
|
314
|
+
expect(detected.length).toBeGreaterThan(0);
|
|
315
|
+
const hasDeepsearch = detected.some(d => d.type === 'deepsearch');
|
|
316
|
+
expect(hasDeepsearch).toBe(true);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
it('should NOT detect deepsearch for generic find', () => {
|
|
320
|
+
const patterns = [
|
|
321
|
+
'find the file',
|
|
322
|
+
'find this function',
|
|
323
|
+
'search for help'
|
|
324
|
+
];
|
|
325
|
+
for (const pattern of patterns) {
|
|
326
|
+
const detected = detectKeywordsWithType(pattern);
|
|
327
|
+
const hasDeepsearch = detected.some(d => d.type === 'deepsearch');
|
|
328
|
+
expect(hasDeepsearch).toBe(false);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
it('should detect analyze patterns with restrictions', () => {
|
|
332
|
+
const patterns = [
|
|
333
|
+
'deep analyze this code',
|
|
334
|
+
'investigate the bug',
|
|
335
|
+
'investigate this issue',
|
|
336
|
+
'debug the problem',
|
|
337
|
+
'debug this error'
|
|
338
|
+
];
|
|
339
|
+
for (const pattern of patterns) {
|
|
340
|
+
const detected = detectKeywordsWithType(pattern);
|
|
341
|
+
expect(detected.length).toBeGreaterThan(0);
|
|
342
|
+
const hasAnalyze = detected.some(d => d.type === 'analyze');
|
|
343
|
+
expect(hasAnalyze).toBe(true);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
it('should NOT detect analyze for generic patterns', () => {
|
|
347
|
+
const patterns = [
|
|
348
|
+
'how to do this',
|
|
349
|
+
'understand this code',
|
|
350
|
+
'review this code',
|
|
351
|
+
'analyze without context'
|
|
352
|
+
];
|
|
353
|
+
for (const pattern of patterns) {
|
|
354
|
+
const detected = detectKeywordsWithType(pattern);
|
|
355
|
+
const hasAnalyze = detected.some(d => d.type === 'analyze');
|
|
356
|
+
expect(hasAnalyze).toBe(false);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
191
359
|
});
|
|
192
360
|
describe('hasKeyword', () => {
|
|
193
361
|
it('should return true when keyword exists', () => {
|
|
194
362
|
expect(hasKeyword('use ultrawork mode')).toBe(true);
|
|
195
|
-
expect(hasKeyword('search
|
|
196
|
-
expect(hasKeyword('
|
|
363
|
+
expect(hasKeyword('search the codebase')).toBe(true);
|
|
364
|
+
expect(hasKeyword('investigate the bug')).toBe(true);
|
|
197
365
|
});
|
|
198
366
|
it('should return false when no keyword exists', () => {
|
|
199
367
|
expect(hasKeyword('just normal text')).toBe(false);
|
|
@@ -204,7 +372,7 @@ describe('Keyword Detector', () => {
|
|
|
204
372
|
expect(hasKeyword(text)).toBe(false);
|
|
205
373
|
});
|
|
206
374
|
it('should detect keywords outside code blocks', () => {
|
|
207
|
-
const text = 'Please search\n```\nsome code\n```\nfor this';
|
|
375
|
+
const text = 'Please search the codebase\n```\nsome code\n```\nfor this';
|
|
208
376
|
expect(hasKeyword(text)).toBe(true);
|
|
209
377
|
});
|
|
210
378
|
it('should handle empty string', () => {
|
|
@@ -219,20 +387,20 @@ describe('Keyword Detector', () => {
|
|
|
219
387
|
expect(primary).not.toBeNull();
|
|
220
388
|
expect(primary.type).toBe('ultrawork');
|
|
221
389
|
});
|
|
222
|
-
it('should return ultrathink when
|
|
223
|
-
const text = '
|
|
390
|
+
it('should return ultrathink when present', () => {
|
|
391
|
+
const text = 'think hard about this problem';
|
|
224
392
|
const primary = getPrimaryKeyword(text);
|
|
225
393
|
expect(primary).not.toBeNull();
|
|
226
394
|
expect(primary.type).toBe('ultrathink');
|
|
227
395
|
});
|
|
228
|
-
it('should return
|
|
229
|
-
const text = 'find
|
|
396
|
+
it('should return deepsearch for codebase search', () => {
|
|
397
|
+
const text = 'find in codebase';
|
|
230
398
|
const primary = getPrimaryKeyword(text);
|
|
231
399
|
expect(primary).not.toBeNull();
|
|
232
|
-
expect(primary.type).toBe('
|
|
400
|
+
expect(primary.type).toBe('deepsearch');
|
|
233
401
|
});
|
|
234
402
|
it('should return analyze when only analyze keyword', () => {
|
|
235
|
-
const text = 'investigate
|
|
403
|
+
const text = 'investigate the issue';
|
|
236
404
|
const primary = getPrimaryKeyword(text);
|
|
237
405
|
expect(primary).not.toBeNull();
|
|
238
406
|
expect(primary.type).toBe('analyze');
|
|
@@ -242,18 +410,89 @@ describe('Keyword Detector', () => {
|
|
|
242
410
|
expect(primary).toBeNull();
|
|
243
411
|
});
|
|
244
412
|
it('should ignore code blocks', () => {
|
|
245
|
-
const text = '```\nultrawork code\n```\nsearch
|
|
413
|
+
const text = '```\nultrawork code\n```\nsearch the codebase';
|
|
246
414
|
const primary = getPrimaryKeyword(text);
|
|
247
415
|
expect(primary).not.toBeNull();
|
|
248
|
-
expect(primary.type).toBe('
|
|
416
|
+
expect(primary.type).toBe('deepsearch');
|
|
249
417
|
});
|
|
250
418
|
it('should return first detected when same priority', () => {
|
|
251
|
-
//
|
|
252
|
-
const text = 'search and
|
|
419
|
+
// deepsearch has higher priority than analyze in the priority list
|
|
420
|
+
const text = 'search the codebase and investigate the bug';
|
|
253
421
|
const primary = getPrimaryKeyword(text);
|
|
254
422
|
expect(primary).not.toBeNull();
|
|
255
|
-
// Should return
|
|
256
|
-
expect(primary.type).toBe('
|
|
423
|
+
// Should return deepsearch as it comes first in priority list
|
|
424
|
+
expect(primary.type).toBe('deepsearch');
|
|
425
|
+
});
|
|
426
|
+
// New priority tests for new keywords
|
|
427
|
+
it('should give cancel highest priority', () => {
|
|
428
|
+
const primary = getPrimaryKeyword('stop searching for files');
|
|
429
|
+
expect(primary).not.toBeNull();
|
|
430
|
+
expect(primary.type).toBe('cancel');
|
|
431
|
+
});
|
|
432
|
+
it('should give cancel priority over analyze', () => {
|
|
433
|
+
const primary = getPrimaryKeyword('cancel this investigation');
|
|
434
|
+
expect(primary).not.toBeNull();
|
|
435
|
+
expect(primary.type).toBe('cancel');
|
|
436
|
+
});
|
|
437
|
+
it('should prioritize cancel over all other keywords', () => {
|
|
438
|
+
const primary = getPrimaryKeyword('stop ultrawork and search');
|
|
439
|
+
expect(primary).not.toBeNull();
|
|
440
|
+
expect(primary.type).toBe('cancel');
|
|
441
|
+
});
|
|
442
|
+
it('should prioritize ralph after cancel', () => {
|
|
443
|
+
const primary = getPrimaryKeyword('ralph mode for the task');
|
|
444
|
+
expect(primary).not.toBeNull();
|
|
445
|
+
expect(primary.type).toBe('ralph');
|
|
446
|
+
});
|
|
447
|
+
it('should prioritize ultrapilot correctly', () => {
|
|
448
|
+
const primary = getPrimaryKeyword('ultrapilot this task');
|
|
449
|
+
expect(primary).not.toBeNull();
|
|
450
|
+
expect(primary.type).toBe('ultrapilot');
|
|
451
|
+
});
|
|
452
|
+
it('should prioritize ecomode correctly', () => {
|
|
453
|
+
const primary = getPrimaryKeyword('use efficient mode for this');
|
|
454
|
+
expect(primary).not.toBeNull();
|
|
455
|
+
expect(primary.type).toBe('ecomode');
|
|
456
|
+
});
|
|
457
|
+
it('should prioritize swarm correctly', () => {
|
|
458
|
+
const primary = getPrimaryKeyword('swarm 5 agents for this');
|
|
459
|
+
expect(primary).not.toBeNull();
|
|
460
|
+
expect(primary.type).toBe('swarm');
|
|
461
|
+
});
|
|
462
|
+
it('should prioritize pipeline correctly', () => {
|
|
463
|
+
const primary = getPrimaryKeyword('pipeline the task');
|
|
464
|
+
expect(primary).not.toBeNull();
|
|
465
|
+
expect(primary.type).toBe('pipeline');
|
|
466
|
+
});
|
|
467
|
+
it('should prioritize ralplan over plan', () => {
|
|
468
|
+
const primary = getPrimaryKeyword('ralplan this project');
|
|
469
|
+
expect(primary).not.toBeNull();
|
|
470
|
+
expect(primary.type).toBe('ralplan');
|
|
471
|
+
});
|
|
472
|
+
it('should detect plan correctly', () => {
|
|
473
|
+
const primary = getPrimaryKeyword('plan this feature');
|
|
474
|
+
expect(primary).not.toBeNull();
|
|
475
|
+
expect(primary.type).toBe('plan');
|
|
476
|
+
});
|
|
477
|
+
it('should prioritize tdd correctly', () => {
|
|
478
|
+
const primary = getPrimaryKeyword('tdd for this feature');
|
|
479
|
+
expect(primary).not.toBeNull();
|
|
480
|
+
expect(primary.type).toBe('tdd');
|
|
481
|
+
});
|
|
482
|
+
it('should prioritize research correctly', () => {
|
|
483
|
+
const primary = getPrimaryKeyword('research this topic');
|
|
484
|
+
expect(primary).not.toBeNull();
|
|
485
|
+
expect(primary.type).toBe('research');
|
|
486
|
+
});
|
|
487
|
+
it('should prioritize deepsearch over generic search', () => {
|
|
488
|
+
const primary = getPrimaryKeyword('search the codebase');
|
|
489
|
+
expect(primary).not.toBeNull();
|
|
490
|
+
expect(primary.type).toBe('deepsearch');
|
|
491
|
+
});
|
|
492
|
+
it('should prioritize analyze with restricted pattern', () => {
|
|
493
|
+
const primary = getPrimaryKeyword('investigate the bug');
|
|
494
|
+
expect(primary).not.toBeNull();
|
|
495
|
+
expect(primary.type).toBe('analyze');
|
|
257
496
|
});
|
|
258
497
|
});
|
|
259
498
|
});
|
|
@@ -577,7 +816,7 @@ describe('Hook Output Structure', () => {
|
|
|
577
816
|
describe('Integration: Keyword Detection with Code Blocks', () => {
|
|
578
817
|
it('should detect keywords outside code and ignore inside', () => {
|
|
579
818
|
const text = `
|
|
580
|
-
Please search
|
|
819
|
+
Please search the codebase
|
|
581
820
|
|
|
582
821
|
\`\`\`javascript
|
|
583
822
|
// This search should be ignored
|
|
@@ -586,25 +825,25 @@ function search() {
|
|
|
586
825
|
}
|
|
587
826
|
\`\`\`
|
|
588
827
|
|
|
589
|
-
Now
|
|
828
|
+
Now investigate the bug
|
|
590
829
|
`;
|
|
591
830
|
const detected = detectKeywordsWithType(removeCodeBlocks(text));
|
|
592
831
|
const types = detected.map(d => d.type);
|
|
593
|
-
expect(types).toContain('
|
|
832
|
+
expect(types).toContain('deepsearch');
|
|
594
833
|
expect(types).toContain('analyze');
|
|
595
834
|
// Should only detect the ones outside code blocks
|
|
596
|
-
expect(detected.filter(d => d.type === '
|
|
835
|
+
expect(detected.filter(d => d.type === 'deepsearch')).toHaveLength(1);
|
|
597
836
|
expect(detected.filter(d => d.type === 'analyze')).toHaveLength(1);
|
|
598
837
|
});
|
|
599
838
|
it('should handle inline code with keywords', () => {
|
|
600
|
-
const text = 'Use the `
|
|
839
|
+
const text = 'Use the `deepsearch` command to find in codebase';
|
|
601
840
|
const cleanText = removeCodeBlocks(text);
|
|
602
841
|
const detected = detectKeywordsWithType(cleanText);
|
|
603
|
-
// The
|
|
604
|
-
expect(detected.some(d => d.type === '
|
|
842
|
+
// The phrase 'find in codebase' should still be detected
|
|
843
|
+
expect(detected.some(d => d.type === 'deepsearch')).toBe(true);
|
|
605
844
|
});
|
|
606
845
|
it('should prioritize ultrawork even with other keywords', () => {
|
|
607
|
-
const text = 'search,
|
|
846
|
+
const text = 'search the codebase, investigate the bug, and use ultrawork mode';
|
|
608
847
|
const primary = getPrimaryKeyword(text);
|
|
609
848
|
expect(primary).not.toBeNull();
|
|
610
849
|
expect(primary.type).toBe('ultrawork');
|
|
@@ -631,33 +870,33 @@ describe('Edge Cases', () => {
|
|
|
631
870
|
});
|
|
632
871
|
describe('Whitespace handling', () => {
|
|
633
872
|
it('should detect keywords with extra whitespace', () => {
|
|
634
|
-
const text = ' search
|
|
873
|
+
const text = ' search the codebase ';
|
|
635
874
|
expect(hasKeyword(text)).toBe(true);
|
|
636
875
|
});
|
|
637
876
|
it('should handle newlines and tabs', () => {
|
|
638
|
-
const text = 'search\n\
|
|
877
|
+
const text = 'search\n\tthe\r\ncodebase';
|
|
639
878
|
const detected = detectKeywordsWithType(text);
|
|
640
|
-
expect(detected.some(d => d.type === '
|
|
879
|
+
expect(detected.some(d => d.type === 'deepsearch')).toBe(true);
|
|
641
880
|
});
|
|
642
881
|
});
|
|
643
882
|
describe('Unicode and special characters', () => {
|
|
644
883
|
it('should handle unicode characters', () => {
|
|
645
|
-
const text = 'search
|
|
884
|
+
const text = 'search the codebase with émojis 🔍';
|
|
646
885
|
expect(hasKeyword(text)).toBe(true);
|
|
647
886
|
});
|
|
648
887
|
it('should handle mixed scripts', () => {
|
|
649
|
-
const text = 'Please search 搜索 искать';
|
|
888
|
+
const text = 'Please search the codebase 搜索 искать';
|
|
650
889
|
const detected = detectKeywordsWithType(text);
|
|
651
|
-
expect(detected.some(d => d.
|
|
890
|
+
expect(detected.some(d => d.type === 'deepsearch')).toBe(true);
|
|
652
891
|
});
|
|
653
892
|
});
|
|
654
893
|
describe('Very long inputs', () => {
|
|
655
894
|
it('should handle long text efficiently', () => {
|
|
656
|
-
const longText = 'plain text '.repeat(1000) + ' search
|
|
895
|
+
const longText = 'plain text '.repeat(1000) + ' search the codebase';
|
|
657
896
|
expect(hasKeyword(longText)).toBe(true);
|
|
658
897
|
});
|
|
659
898
|
it('should handle many code blocks', () => {
|
|
660
|
-
const manyBlocks = '```code```\n'.repeat(100) + 'search
|
|
899
|
+
const manyBlocks = '```code```\n'.repeat(100) + 'search the codebase';
|
|
661
900
|
const cleaned = removeCodeBlocks(manyBlocks);
|
|
662
901
|
expect(hasKeyword(cleaned)).toBe(true);
|
|
663
902
|
});
|