oh-my-claude-sisyphus 3.7.15 → 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 +9 -4
- 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/bridge/mcp-server.cjs +57 -1
- 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 +338 -83
- package/dist/__tests__/hooks.test.js.map +1 -1
- package/dist/__tests__/installer.test.js +32 -16
- package/dist/__tests__/installer.test.js.map +1 -1
- package/dist/__tests__/lsp-servers.test.d.ts +2 -0
- package/dist/__tests__/lsp-servers.test.d.ts.map +1 -0
- package/dist/__tests__/lsp-servers.test.js +118 -0
- package/dist/__tests__/lsp-servers.test.js.map +1 -0
- package/dist/__tests__/task-continuation.test.d.ts +2 -0
- package/dist/__tests__/task-continuation.test.d.ts.map +1 -0
- package/dist/__tests__/task-continuation.test.js +740 -0
- package/dist/__tests__/task-continuation.test.js.map +1 -0
- 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/dist/hooks/persistent-mode/index.d.ts.map +1 -1
- package/dist/hooks/persistent-mode/index.js +6 -3
- package/dist/hooks/persistent-mode/index.js.map +1 -1
- package/dist/hooks/todo-continuation/index.d.ts +111 -3
- package/dist/hooks/todo-continuation/index.d.ts.map +1 -1
- package/dist/hooks/todo-continuation/index.js +204 -23
- package/dist/hooks/todo-continuation/index.js.map +1 -1
- package/dist/installer/index.d.ts +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +1 -1
- package/dist/installer/index.js.map +1 -1
- package/dist/tools/lsp/client.d.ts.map +1 -1
- package/dist/tools/lsp/client.js +15 -1
- package/dist/tools/lsp/client.js.map +1 -1
- package/dist/tools/lsp/servers.d.ts.map +1 -1
- package/dist/tools/lsp/servers.js +62 -1
- package/dist/tools/lsp/servers.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
- package/templates/hooks/persistent-mode.mjs +57 -7
- package/templates/hooks/persistent-mode.sh +62 -5
- package/templates/hooks/stop-continuation.mjs +65 -8
- package/templates/hooks/stop-continuation.sh +57 -4
|
@@ -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
|
});
|
|
@@ -263,7 +502,8 @@ describe('Todo Continuation', () => {
|
|
|
263
502
|
const result = {
|
|
264
503
|
count: 0,
|
|
265
504
|
todos: [],
|
|
266
|
-
total: 5
|
|
505
|
+
total: 5,
|
|
506
|
+
source: 'todo'
|
|
267
507
|
};
|
|
268
508
|
expect(formatTodoStatus(result)).toBe('All tasks complete (5 total)');
|
|
269
509
|
});
|
|
@@ -271,7 +511,8 @@ describe('Todo Continuation', () => {
|
|
|
271
511
|
const result = {
|
|
272
512
|
count: 3,
|
|
273
513
|
todos: [],
|
|
274
|
-
total: 10
|
|
514
|
+
total: 10,
|
|
515
|
+
source: 'todo'
|
|
275
516
|
};
|
|
276
517
|
expect(formatTodoStatus(result)).toBe('7/10 completed, 3 remaining');
|
|
277
518
|
});
|
|
@@ -279,7 +520,8 @@ describe('Todo Continuation', () => {
|
|
|
279
520
|
const result = {
|
|
280
521
|
count: 0,
|
|
281
522
|
todos: [],
|
|
282
|
-
total: 0
|
|
523
|
+
total: 0,
|
|
524
|
+
source: 'none'
|
|
283
525
|
};
|
|
284
526
|
expect(formatTodoStatus(result)).toBe('All tasks complete (0 total)');
|
|
285
527
|
});
|
|
@@ -287,7 +529,8 @@ describe('Todo Continuation', () => {
|
|
|
287
529
|
const result = {
|
|
288
530
|
count: 5,
|
|
289
531
|
todos: [],
|
|
290
|
-
total: 5
|
|
532
|
+
total: 5,
|
|
533
|
+
source: 'todo'
|
|
291
534
|
};
|
|
292
535
|
expect(formatTodoStatus(result)).toBe('0/5 completed, 5 remaining');
|
|
293
536
|
});
|
|
@@ -295,7 +538,8 @@ describe('Todo Continuation', () => {
|
|
|
295
538
|
const result = {
|
|
296
539
|
count: 1,
|
|
297
540
|
todos: [],
|
|
298
|
-
total: 10
|
|
541
|
+
total: 10,
|
|
542
|
+
source: 'todo'
|
|
299
543
|
};
|
|
300
544
|
expect(formatTodoStatus(result)).toBe('9/10 completed, 1 remaining');
|
|
301
545
|
});
|
|
@@ -310,7 +554,8 @@ describe('Todo Continuation', () => {
|
|
|
310
554
|
const result = {
|
|
311
555
|
count: 3,
|
|
312
556
|
todos,
|
|
313
|
-
total: 3
|
|
557
|
+
total: 3,
|
|
558
|
+
source: 'todo'
|
|
314
559
|
};
|
|
315
560
|
const next = getNextPendingTodo(result);
|
|
316
561
|
expect(next).not.toBeNull();
|
|
@@ -326,7 +571,8 @@ describe('Todo Continuation', () => {
|
|
|
326
571
|
const result = {
|
|
327
572
|
count: 2,
|
|
328
573
|
todos: todos.filter(t => t.status !== 'completed'),
|
|
329
|
-
total: 3
|
|
574
|
+
total: 3,
|
|
575
|
+
source: 'todo'
|
|
330
576
|
};
|
|
331
577
|
const next = getNextPendingTodo(result);
|
|
332
578
|
expect(next).not.toBeNull();
|
|
@@ -337,7 +583,8 @@ describe('Todo Continuation', () => {
|
|
|
337
583
|
const result = {
|
|
338
584
|
count: 0,
|
|
339
585
|
todos: [],
|
|
340
|
-
total: 0
|
|
586
|
+
total: 0,
|
|
587
|
+
source: 'none'
|
|
341
588
|
};
|
|
342
589
|
const next = getNextPendingTodo(result);
|
|
343
590
|
expect(next).toBeNull();
|
|
@@ -346,7 +593,8 @@ describe('Todo Continuation', () => {
|
|
|
346
593
|
const result = {
|
|
347
594
|
count: 0,
|
|
348
595
|
todos: [],
|
|
349
|
-
total: 3
|
|
596
|
+
total: 3,
|
|
597
|
+
source: 'todo'
|
|
350
598
|
};
|
|
351
599
|
const next = getNextPendingTodo(result);
|
|
352
600
|
expect(next).toBeNull();
|
|
@@ -359,7 +607,8 @@ describe('Todo Continuation', () => {
|
|
|
359
607
|
const result = {
|
|
360
608
|
count: 2,
|
|
361
609
|
todos,
|
|
362
|
-
total: 2
|
|
610
|
+
total: 2,
|
|
611
|
+
source: 'todo'
|
|
363
612
|
};
|
|
364
613
|
const next = getNextPendingTodo(result);
|
|
365
614
|
expect(next).not.toBeNull();
|
|
@@ -373,7 +622,8 @@ describe('Todo Continuation', () => {
|
|
|
373
622
|
const result = {
|
|
374
623
|
count: 2,
|
|
375
624
|
todos,
|
|
376
|
-
total: 2
|
|
625
|
+
total: 2,
|
|
626
|
+
source: 'todo'
|
|
377
627
|
};
|
|
378
628
|
const next = getNextPendingTodo(result);
|
|
379
629
|
expect(next).not.toBeNull();
|
|
@@ -387,7 +637,8 @@ describe('Todo Continuation', () => {
|
|
|
387
637
|
const result = {
|
|
388
638
|
count: 1,
|
|
389
639
|
todos: [todos[1]],
|
|
390
|
-
total: 2
|
|
640
|
+
total: 2,
|
|
641
|
+
source: 'todo'
|
|
391
642
|
};
|
|
392
643
|
const next = getNextPendingTodo(result);
|
|
393
644
|
expect(next).not.toBeNull();
|
|
@@ -403,7 +654,8 @@ describe('Todo Continuation', () => {
|
|
|
403
654
|
const result = {
|
|
404
655
|
count: 4,
|
|
405
656
|
todos,
|
|
406
|
-
total: 4
|
|
657
|
+
total: 4,
|
|
658
|
+
source: 'todo'
|
|
407
659
|
};
|
|
408
660
|
const next = getNextPendingTodo(result);
|
|
409
661
|
expect(next).not.toBeNull();
|
|
@@ -456,7 +708,8 @@ describe('Todo Continuation', () => {
|
|
|
456
708
|
const result = {
|
|
457
709
|
count: todos.length,
|
|
458
710
|
todos,
|
|
459
|
-
total: 5
|
|
711
|
+
total: 5,
|
|
712
|
+
source: 'todo'
|
|
460
713
|
};
|
|
461
714
|
expect(result.count).toBe(result.todos.length);
|
|
462
715
|
expect(result.total).toBeGreaterThanOrEqual(result.count);
|
|
@@ -466,7 +719,8 @@ describe('Todo Continuation', () => {
|
|
|
466
719
|
const result = {
|
|
467
720
|
count: 0,
|
|
468
721
|
todos: [],
|
|
469
|
-
total: 3
|
|
722
|
+
total: 3,
|
|
723
|
+
source: 'todo'
|
|
470
724
|
};
|
|
471
725
|
expect(result.count).toBeLessThanOrEqual(result.total);
|
|
472
726
|
});
|
|
@@ -549,7 +803,8 @@ describe('Hook Output Structure', () => {
|
|
|
549
803
|
const result = {
|
|
550
804
|
count: 2,
|
|
551
805
|
todos: [],
|
|
552
|
-
total: 5
|
|
806
|
+
total: 5,
|
|
807
|
+
source: 'todo'
|
|
553
808
|
};
|
|
554
809
|
const status = formatTodoStatus(result);
|
|
555
810
|
const message = `Todo Status: ${status}`;
|
|
@@ -561,7 +816,7 @@ describe('Hook Output Structure', () => {
|
|
|
561
816
|
describe('Integration: Keyword Detection with Code Blocks', () => {
|
|
562
817
|
it('should detect keywords outside code and ignore inside', () => {
|
|
563
818
|
const text = `
|
|
564
|
-
Please search
|
|
819
|
+
Please search the codebase
|
|
565
820
|
|
|
566
821
|
\`\`\`javascript
|
|
567
822
|
// This search should be ignored
|
|
@@ -570,25 +825,25 @@ function search() {
|
|
|
570
825
|
}
|
|
571
826
|
\`\`\`
|
|
572
827
|
|
|
573
|
-
Now
|
|
828
|
+
Now investigate the bug
|
|
574
829
|
`;
|
|
575
830
|
const detected = detectKeywordsWithType(removeCodeBlocks(text));
|
|
576
831
|
const types = detected.map(d => d.type);
|
|
577
|
-
expect(types).toContain('
|
|
832
|
+
expect(types).toContain('deepsearch');
|
|
578
833
|
expect(types).toContain('analyze');
|
|
579
834
|
// Should only detect the ones outside code blocks
|
|
580
|
-
expect(detected.filter(d => d.type === '
|
|
835
|
+
expect(detected.filter(d => d.type === 'deepsearch')).toHaveLength(1);
|
|
581
836
|
expect(detected.filter(d => d.type === 'analyze')).toHaveLength(1);
|
|
582
837
|
});
|
|
583
838
|
it('should handle inline code with keywords', () => {
|
|
584
|
-
const text = 'Use the `
|
|
839
|
+
const text = 'Use the `deepsearch` command to find in codebase';
|
|
585
840
|
const cleanText = removeCodeBlocks(text);
|
|
586
841
|
const detected = detectKeywordsWithType(cleanText);
|
|
587
|
-
// The
|
|
588
|
-
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);
|
|
589
844
|
});
|
|
590
845
|
it('should prioritize ultrawork even with other keywords', () => {
|
|
591
|
-
const text = 'search,
|
|
846
|
+
const text = 'search the codebase, investigate the bug, and use ultrawork mode';
|
|
592
847
|
const primary = getPrimaryKeyword(text);
|
|
593
848
|
expect(primary).not.toBeNull();
|
|
594
849
|
expect(primary.type).toBe('ultrawork');
|
|
@@ -615,33 +870,33 @@ describe('Edge Cases', () => {
|
|
|
615
870
|
});
|
|
616
871
|
describe('Whitespace handling', () => {
|
|
617
872
|
it('should detect keywords with extra whitespace', () => {
|
|
618
|
-
const text = ' search
|
|
873
|
+
const text = ' search the codebase ';
|
|
619
874
|
expect(hasKeyword(text)).toBe(true);
|
|
620
875
|
});
|
|
621
876
|
it('should handle newlines and tabs', () => {
|
|
622
|
-
const text = 'search\n\
|
|
877
|
+
const text = 'search\n\tthe\r\ncodebase';
|
|
623
878
|
const detected = detectKeywordsWithType(text);
|
|
624
|
-
expect(detected.some(d => d.type === '
|
|
879
|
+
expect(detected.some(d => d.type === 'deepsearch')).toBe(true);
|
|
625
880
|
});
|
|
626
881
|
});
|
|
627
882
|
describe('Unicode and special characters', () => {
|
|
628
883
|
it('should handle unicode characters', () => {
|
|
629
|
-
const text = 'search
|
|
884
|
+
const text = 'search the codebase with émojis 🔍';
|
|
630
885
|
expect(hasKeyword(text)).toBe(true);
|
|
631
886
|
});
|
|
632
887
|
it('should handle mixed scripts', () => {
|
|
633
|
-
const text = 'Please search 搜索 искать';
|
|
888
|
+
const text = 'Please search the codebase 搜索 искать';
|
|
634
889
|
const detected = detectKeywordsWithType(text);
|
|
635
|
-
expect(detected.some(d => d.
|
|
890
|
+
expect(detected.some(d => d.type === 'deepsearch')).toBe(true);
|
|
636
891
|
});
|
|
637
892
|
});
|
|
638
893
|
describe('Very long inputs', () => {
|
|
639
894
|
it('should handle long text efficiently', () => {
|
|
640
|
-
const longText = 'plain text '.repeat(1000) + ' search
|
|
895
|
+
const longText = 'plain text '.repeat(1000) + ' search the codebase';
|
|
641
896
|
expect(hasKeyword(longText)).toBe(true);
|
|
642
897
|
});
|
|
643
898
|
it('should handle many code blocks', () => {
|
|
644
|
-
const manyBlocks = '```code```\n'.repeat(100) + 'search
|
|
899
|
+
const manyBlocks = '```code```\n'.repeat(100) + 'search the codebase';
|
|
645
900
|
const cleaned = removeCodeBlocks(manyBlocks);
|
|
646
901
|
expect(hasKeyword(cleaned)).toBe(true);
|
|
647
902
|
});
|