oh-my-claude-sisyphus 1.11.2 → 2.0.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.
Files changed (207) hide show
  1. package/README.md +37 -12
  2. package/dist/__tests__/example.test.d.ts +2 -0
  3. package/dist/__tests__/example.test.d.ts.map +1 -0
  4. package/dist/__tests__/example.test.js +20 -0
  5. package/dist/__tests__/example.test.js.map +1 -0
  6. package/dist/__tests__/hooks.test.d.ts +2 -0
  7. package/dist/__tests__/hooks.test.d.ts.map +1 -0
  8. package/dist/__tests__/hooks.test.js +644 -0
  9. package/dist/__tests__/hooks.test.js.map +1 -0
  10. package/dist/__tests__/installer.test.d.ts +2 -0
  11. package/dist/__tests__/installer.test.d.ts.map +1 -0
  12. package/dist/__tests__/installer.test.js +369 -0
  13. package/dist/__tests__/installer.test.js.map +1 -0
  14. package/dist/__tests__/model-routing.test.d.ts +2 -0
  15. package/dist/__tests__/model-routing.test.d.ts.map +1 -0
  16. package/dist/__tests__/model-routing.test.js +814 -0
  17. package/dist/__tests__/model-routing.test.js.map +1 -0
  18. package/dist/__tests__/skills.test.d.ts +2 -0
  19. package/dist/__tests__/skills.test.d.ts.map +1 -0
  20. package/dist/__tests__/skills.test.js +126 -0
  21. package/dist/__tests__/skills.test.js.map +1 -0
  22. package/dist/__tests__/types.test.d.ts +2 -0
  23. package/dist/__tests__/types.test.d.ts.map +1 -0
  24. package/dist/__tests__/types.test.js +77 -0
  25. package/dist/__tests__/types.test.js.map +1 -0
  26. package/dist/agents/definitions.d.ts +1 -1
  27. package/dist/agents/definitions.d.ts.map +1 -1
  28. package/dist/agents/definitions.js +35 -3
  29. package/dist/agents/definitions.js.map +1 -1
  30. package/dist/agents/index.d.ts +1 -1
  31. package/dist/agents/index.d.ts.map +1 -1
  32. package/dist/agents/index.js +3 -1
  33. package/dist/agents/index.js.map +1 -1
  34. package/dist/agents/oracle.d.ts.map +1 -1
  35. package/dist/agents/oracle.js +43 -1
  36. package/dist/agents/oracle.js.map +1 -1
  37. package/dist/agents/orchestrator-sisyphus.js +2 -2
  38. package/dist/agents/orchestrator-sisyphus.js.map +1 -1
  39. package/dist/cli/index.js +22 -11
  40. package/dist/cli/index.js.map +1 -1
  41. package/dist/config/loader.d.ts.map +1 -1
  42. package/dist/config/loader.js +49 -0
  43. package/dist/config/loader.js.map +1 -1
  44. package/dist/features/auto-update.d.ts.map +1 -1
  45. package/dist/features/auto-update.js +14 -3
  46. package/dist/features/auto-update.js.map +1 -1
  47. package/dist/features/builtin-skills/skills.d.ts.map +1 -1
  48. package/dist/features/builtin-skills/skills.js +0 -1351
  49. package/dist/features/builtin-skills/skills.js.map +1 -1
  50. package/dist/features/index.d.ts +1 -0
  51. package/dist/features/index.d.ts.map +1 -1
  52. package/dist/features/index.js +14 -0
  53. package/dist/features/index.js.map +1 -1
  54. package/dist/features/model-routing/index.d.ts +34 -0
  55. package/dist/features/model-routing/index.d.ts.map +1 -0
  56. package/dist/features/model-routing/index.js +48 -0
  57. package/dist/features/model-routing/index.js.map +1 -0
  58. package/dist/features/model-routing/prompts/haiku.d.ts +54 -0
  59. package/dist/features/model-routing/prompts/haiku.d.ts.map +1 -0
  60. package/dist/features/model-routing/prompts/haiku.js +141 -0
  61. package/dist/features/model-routing/prompts/haiku.js.map +1 -0
  62. package/dist/features/model-routing/prompts/index.d.ts +45 -0
  63. package/dist/features/model-routing/prompts/index.d.ts.map +1 -0
  64. package/dist/features/model-routing/prompts/index.js +116 -0
  65. package/dist/features/model-routing/prompts/index.js.map +1 -0
  66. package/dist/features/model-routing/prompts/opus.d.ts +34 -0
  67. package/dist/features/model-routing/prompts/opus.d.ts.map +1 -0
  68. package/dist/features/model-routing/prompts/opus.js +153 -0
  69. package/dist/features/model-routing/prompts/opus.js.map +1 -0
  70. package/dist/features/model-routing/prompts/sonnet.d.ts +38 -0
  71. package/dist/features/model-routing/prompts/sonnet.d.ts.map +1 -0
  72. package/dist/features/model-routing/prompts/sonnet.js +149 -0
  73. package/dist/features/model-routing/prompts/sonnet.js.map +1 -0
  74. package/dist/features/model-routing/router.d.ts +92 -0
  75. package/dist/features/model-routing/router.d.ts.map +1 -0
  76. package/dist/features/model-routing/router.js +267 -0
  77. package/dist/features/model-routing/router.js.map +1 -0
  78. package/dist/features/model-routing/rules.d.ts +32 -0
  79. package/dist/features/model-routing/rules.d.ts.map +1 -0
  80. package/dist/features/model-routing/rules.js +224 -0
  81. package/dist/features/model-routing/rules.js.map +1 -0
  82. package/dist/features/model-routing/scorer.d.ts +35 -0
  83. package/dist/features/model-routing/scorer.d.ts.map +1 -0
  84. package/dist/features/model-routing/scorer.js +241 -0
  85. package/dist/features/model-routing/scorer.js.map +1 -0
  86. package/dist/features/model-routing/signals.d.ts +26 -0
  87. package/dist/features/model-routing/signals.d.ts.map +1 -0
  88. package/dist/features/model-routing/signals.js +283 -0
  89. package/dist/features/model-routing/signals.js.map +1 -0
  90. package/dist/features/model-routing/types.d.ts +195 -0
  91. package/dist/features/model-routing/types.d.ts.map +1 -0
  92. package/dist/features/model-routing/types.js +86 -0
  93. package/dist/features/model-routing/types.js.map +1 -0
  94. package/dist/hooks/agent-usage-reminder/index.d.ts +1 -1
  95. package/dist/hooks/agent-usage-reminder/index.d.ts.map +1 -1
  96. package/dist/hooks/agent-usage-reminder/index.js +1 -1
  97. package/dist/hooks/agent-usage-reminder/index.js.map +1 -1
  98. package/dist/hooks/auto-slash-command/executor.js.map +1 -1
  99. package/dist/hooks/auto-slash-command/index.d.ts +3 -3
  100. package/dist/hooks/auto-slash-command/index.d.ts.map +1 -1
  101. package/dist/hooks/auto-slash-command/index.js.map +1 -1
  102. package/dist/hooks/background-notification/index.js +1 -1
  103. package/dist/hooks/background-notification/index.js.map +1 -1
  104. package/dist/hooks/bridge.d.ts.map +1 -1
  105. package/dist/hooks/bridge.js.map +1 -1
  106. package/dist/hooks/comment-checker/filters.d.ts +1 -1
  107. package/dist/hooks/comment-checker/filters.d.ts.map +1 -1
  108. package/dist/hooks/comment-checker/filters.js +1 -1
  109. package/dist/hooks/comment-checker/filters.js.map +1 -1
  110. package/dist/hooks/comment-checker/index.js +1 -1
  111. package/dist/hooks/comment-checker/index.js.map +1 -1
  112. package/dist/hooks/context-window-limit-recovery/index.d.ts.map +1 -1
  113. package/dist/hooks/context-window-limit-recovery/index.js.map +1 -1
  114. package/dist/hooks/index.d.ts +3 -3
  115. package/dist/hooks/index.d.ts.map +1 -1
  116. package/dist/hooks/index.js +3 -3
  117. package/dist/hooks/index.js.map +1 -1
  118. package/dist/hooks/keyword-detector/index.d.ts +1 -1
  119. package/dist/hooks/keyword-detector/index.d.ts.map +1 -1
  120. package/dist/hooks/keyword-detector/index.js +1 -1
  121. package/dist/hooks/keyword-detector/index.js.map +1 -1
  122. package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
  123. package/dist/hooks/persistent-mode/index.js.map +1 -1
  124. package/dist/hooks/plugin-patterns/index.d.ts.map +1 -1
  125. package/dist/hooks/plugin-patterns/index.js +12 -22
  126. package/dist/hooks/plugin-patterns/index.js.map +1 -1
  127. package/dist/hooks/preemptive-compaction/index.d.ts +2 -2
  128. package/dist/hooks/preemptive-compaction/index.d.ts.map +1 -1
  129. package/dist/hooks/preemptive-compaction/index.js +1 -11
  130. package/dist/hooks/preemptive-compaction/index.js.map +1 -1
  131. package/dist/hooks/ralph-loop/index.js.map +1 -1
  132. package/dist/hooks/rules-injector/matcher.js +1 -1
  133. package/dist/hooks/rules-injector/matcher.js.map +1 -1
  134. package/dist/hooks/session-recovery/index.d.ts +1 -1
  135. package/dist/hooks/session-recovery/index.d.ts.map +1 -1
  136. package/dist/hooks/session-recovery/index.js +1 -1
  137. package/dist/hooks/session-recovery/index.js.map +1 -1
  138. package/dist/hooks/sisyphus-orchestrator/index.d.ts.map +1 -1
  139. package/dist/hooks/sisyphus-orchestrator/index.js.map +1 -1
  140. package/dist/hooks/ultrawork-state/index.js +1 -1
  141. package/dist/hooks/ultrawork-state/index.js.map +1 -1
  142. package/dist/index.d.ts +2 -2
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.js +4 -2
  145. package/dist/index.js.map +1 -1
  146. package/dist/installer/hooks.d.ts +1 -1
  147. package/dist/installer/hooks.js +1 -1
  148. package/dist/installer/index.d.ts +8 -7
  149. package/dist/installer/index.d.ts.map +1 -1
  150. package/dist/installer/index.js +648 -2141
  151. package/dist/installer/index.js.map +1 -1
  152. package/dist/shared/types.d.ts +25 -0
  153. package/dist/shared/types.d.ts.map +1 -1
  154. package/dist/tools/lsp/servers.d.ts.map +1 -1
  155. package/dist/tools/lsp/servers.js +2 -14
  156. package/dist/tools/lsp/servers.js.map +1 -1
  157. package/package.json +18 -10
  158. package/scripts/install.sh +236 -260
  159. package/scripts/test-pr25.sh +525 -0
  160. package/dist/agents/model-lists.d.ts +0 -26
  161. package/dist/agents/model-lists.d.ts.map +0 -1
  162. package/dist/agents/model-lists.js +0 -62
  163. package/dist/agents/model-lists.js.map +0 -1
  164. package/dist/auth/index.d.ts +0 -10
  165. package/dist/auth/index.d.ts.map +0 -1
  166. package/dist/auth/index.js +0 -13
  167. package/dist/auth/index.js.map +0 -1
  168. package/dist/auth/manager.d.ts +0 -54
  169. package/dist/auth/manager.d.ts.map +0 -1
  170. package/dist/auth/manager.js +0 -248
  171. package/dist/auth/manager.js.map +0 -1
  172. package/dist/auth/oauth-google.d.ts +0 -47
  173. package/dist/auth/oauth-google.d.ts.map +0 -1
  174. package/dist/auth/oauth-google.js +0 -280
  175. package/dist/auth/oauth-google.js.map +0 -1
  176. package/dist/auth/oauth-openai.d.ts +0 -46
  177. package/dist/auth/oauth-openai.d.ts.map +0 -1
  178. package/dist/auth/oauth-openai.js +0 -264
  179. package/dist/auth/oauth-openai.js.map +0 -1
  180. package/dist/auth/pkce.d.ts +0 -14
  181. package/dist/auth/pkce.d.ts.map +0 -1
  182. package/dist/auth/pkce.js +0 -35
  183. package/dist/auth/pkce.js.map +0 -1
  184. package/dist/auth/storage.d.ts +0 -52
  185. package/dist/auth/storage.d.ts.map +0 -1
  186. package/dist/auth/storage.js +0 -230
  187. package/dist/auth/storage.js.map +0 -1
  188. package/dist/auth/types.d.ts +0 -76
  189. package/dist/auth/types.d.ts.map +0 -1
  190. package/dist/auth/types.js +0 -5
  191. package/dist/auth/types.js.map +0 -1
  192. package/dist/providers/index.d.ts +0 -8
  193. package/dist/providers/index.d.ts.map +0 -1
  194. package/dist/providers/index.js +0 -10
  195. package/dist/providers/index.js.map +0 -1
  196. package/dist/providers/registry.d.ts +0 -29
  197. package/dist/providers/registry.d.ts.map +0 -1
  198. package/dist/providers/registry.js +0 -162
  199. package/dist/providers/registry.js.map +0 -1
  200. package/dist/providers/router.d.ts +0 -40
  201. package/dist/providers/router.d.ts.map +0 -1
  202. package/dist/providers/router.js +0 -88
  203. package/dist/providers/router.js.map +0 -1
  204. package/dist/providers/types.d.ts +0 -92
  205. package/dist/providers/types.d.ts.map +0 -1
  206. package/dist/providers/types.js +0 -27
  207. package/dist/providers/types.js.map +0 -1
@@ -0,0 +1,814 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { extractLexicalSignals, extractStructuralSignals, extractContextSignals, extractAllSignals, } from '../features/model-routing/signals.js';
3
+ import { calculateComplexityScore, scoreToTier, calculateComplexityTier, getScoreBreakdown, calculateConfidence, } from '../features/model-routing/scorer.js';
4
+ import { evaluateRules, getMatchingRules, createRule, mergeRules, DEFAULT_ROUTING_RULES, } from '../features/model-routing/rules.js';
5
+ import { routeTask, escalateModel, canEscalate, getModelForTask, quickTierForAgent, isFixedTierAgent, analyzeTaskComplexity, } from '../features/model-routing/router.js';
6
+ // ============ Signal Extraction Tests ============
7
+ describe('Signal Extraction', () => {
8
+ describe('extractLexicalSignals', () => {
9
+ it('should count words correctly', () => {
10
+ const signals = extractLexicalSignals('Hello world this is a test');
11
+ expect(signals.wordCount).toBe(6);
12
+ });
13
+ it('should handle empty string', () => {
14
+ const signals = extractLexicalSignals('');
15
+ expect(signals.wordCount).toBe(0);
16
+ });
17
+ it('should count file paths', () => {
18
+ const prompt = 'Check src/file.ts and lib/utils.js';
19
+ const signals = extractLexicalSignals(prompt);
20
+ expect(signals.filePathCount).toBeGreaterThan(0);
21
+ });
22
+ it('should count code blocks', () => {
23
+ const prompt = 'Here is code:\n```js\nfunction test() {}\n```\nAnd more:\n```ts\nconst x = 1;\n```';
24
+ const signals = extractLexicalSignals(prompt);
25
+ expect(signals.codeBlockCount).toBe(2);
26
+ });
27
+ it('should detect architecture keywords', () => {
28
+ const signals = extractLexicalSignals('We need to refactor the architecture');
29
+ expect(signals.hasArchitectureKeywords).toBe(true);
30
+ });
31
+ it('should detect debugging keywords', () => {
32
+ const signals = extractLexicalSignals('Debug this issue and find the root cause');
33
+ expect(signals.hasDebuggingKeywords).toBe(true);
34
+ });
35
+ it('should detect simple keywords', () => {
36
+ const signals = extractLexicalSignals('Find the file and show me the contents');
37
+ expect(signals.hasSimpleKeywords).toBe(true);
38
+ });
39
+ it('should detect risk keywords', () => {
40
+ const signals = extractLexicalSignals('This is a critical production migration');
41
+ expect(signals.hasRiskKeywords).toBe(true);
42
+ });
43
+ it('should detect question depth - why', () => {
44
+ const signals = extractLexicalSignals('Why is this not working?');
45
+ expect(signals.questionDepth).toBe('why');
46
+ });
47
+ it('should detect question depth - how', () => {
48
+ const signals = extractLexicalSignals('How do I implement this feature?');
49
+ expect(signals.questionDepth).toBe('how');
50
+ });
51
+ it('should detect question depth - what', () => {
52
+ const signals = extractLexicalSignals('What is the purpose of this?');
53
+ expect(signals.questionDepth).toBe('what');
54
+ });
55
+ it('should detect question depth - where', () => {
56
+ const signals = extractLexicalSignals('Where is the configuration file?');
57
+ expect(signals.questionDepth).toBe('where');
58
+ });
59
+ it('should return none for no questions', () => {
60
+ const signals = extractLexicalSignals('Implement this feature');
61
+ expect(signals.questionDepth).toBe('none');
62
+ });
63
+ it('should detect implicit requirements', () => {
64
+ const signals = extractLexicalSignals('Make it better and clean up the code');
65
+ expect(signals.hasImplicitRequirements).toBe(true);
66
+ });
67
+ it('should not detect implicit requirements in specific tasks', () => {
68
+ const signals = extractLexicalSignals('Fix the bug in utils.ts by adding null check');
69
+ expect(signals.hasImplicitRequirements).toBe(false);
70
+ });
71
+ });
72
+ describe('extractStructuralSignals', () => {
73
+ it('should estimate subtasks from bullet points', () => {
74
+ const prompt = '- Task 1\n- Task 2\n- Task 3';
75
+ const signals = extractStructuralSignals(prompt);
76
+ expect(signals.estimatedSubtasks).toBeGreaterThan(1);
77
+ });
78
+ it('should estimate subtasks from numbered list', () => {
79
+ const prompt = '1. First task\n2. Second task\n3. Third task';
80
+ const signals = extractStructuralSignals(prompt);
81
+ expect(signals.estimatedSubtasks).toBeGreaterThan(1);
82
+ });
83
+ it('should detect cross-file dependencies', () => {
84
+ const prompt = 'Update src/a.ts and src/b.ts and src/c.ts';
85
+ const signals = extractStructuralSignals(prompt);
86
+ expect(signals.crossFileDependencies).toBe(true);
87
+ });
88
+ it('should detect test requirements', () => {
89
+ const signals = extractStructuralSignals('Add feature and make sure tests pass');
90
+ expect(signals.hasTestRequirements).toBe(true);
91
+ });
92
+ it('should detect frontend domain', () => {
93
+ const signals = extractStructuralSignals('Create a React component with styled CSS');
94
+ expect(signals.domainSpecificity).toBe('frontend');
95
+ });
96
+ it('should detect backend domain', () => {
97
+ const signals = extractStructuralSignals('Create an API endpoint with database query');
98
+ expect(signals.domainSpecificity).toBe('backend');
99
+ });
100
+ it('should detect infrastructure domain', () => {
101
+ const signals = extractStructuralSignals('Set up Docker container with Kubernetes');
102
+ expect(signals.domainSpecificity).toBe('infrastructure');
103
+ });
104
+ it('should detect security domain', () => {
105
+ const signals = extractStructuralSignals('Fix the authentication vulnerability');
106
+ expect(signals.domainSpecificity).toBe('security');
107
+ });
108
+ it('should detect external knowledge requirement', () => {
109
+ const signals = extractStructuralSignals('Check the documentation for best practices');
110
+ expect(signals.requiresExternalKnowledge).toBe(true);
111
+ });
112
+ it('should assess reversibility as difficult', () => {
113
+ const signals = extractStructuralSignals('Run the production migration');
114
+ expect(signals.reversibility).toBe('difficult');
115
+ });
116
+ it('should assess reversibility as moderate', () => {
117
+ const signals = extractStructuralSignals('Refactor the entire module structure');
118
+ expect(signals.reversibility).toBe('moderate');
119
+ });
120
+ it('should assess reversibility as easy', () => {
121
+ const signals = extractStructuralSignals('Add a console log statement');
122
+ expect(signals.reversibility).toBe('easy');
123
+ });
124
+ it('should detect system-wide impact', () => {
125
+ const signals = extractStructuralSignals('Change global configuration throughout the codebase');
126
+ expect(signals.impactScope).toBe('system-wide');
127
+ });
128
+ it('should detect module-level impact', () => {
129
+ const signals = extractStructuralSignals('Update the auth module and service layer');
130
+ expect(signals.impactScope).toBe('module');
131
+ });
132
+ it('should detect local impact', () => {
133
+ const signals = extractStructuralSignals('Fix the typo in this function');
134
+ expect(signals.impactScope).toBe('local');
135
+ });
136
+ });
137
+ describe('extractContextSignals', () => {
138
+ it('should extract context signals', () => {
139
+ const context = {
140
+ taskPrompt: 'test',
141
+ previousFailures: 2,
142
+ conversationTurns: 5,
143
+ planTasks: 10,
144
+ remainingTasks: 3,
145
+ agentChainDepth: 2,
146
+ };
147
+ const signals = extractContextSignals(context);
148
+ expect(signals.previousFailures).toBe(2);
149
+ expect(signals.conversationTurns).toBe(5);
150
+ expect(signals.planComplexity).toBe(10);
151
+ expect(signals.remainingTasks).toBe(3);
152
+ expect(signals.agentChainDepth).toBe(2);
153
+ });
154
+ it('should handle missing context values', () => {
155
+ const context = {
156
+ taskPrompt: 'test',
157
+ };
158
+ const signals = extractContextSignals(context);
159
+ expect(signals.previousFailures).toBe(0);
160
+ expect(signals.conversationTurns).toBe(0);
161
+ expect(signals.planComplexity).toBe(0);
162
+ expect(signals.remainingTasks).toBe(0);
163
+ expect(signals.agentChainDepth).toBe(0);
164
+ });
165
+ });
166
+ describe('extractAllSignals', () => {
167
+ it('should combine all signal types', () => {
168
+ const context = {
169
+ taskPrompt: 'Refactor the architecture with multiple files',
170
+ previousFailures: 1,
171
+ };
172
+ const signals = extractAllSignals(context.taskPrompt, context);
173
+ expect(signals.lexical).toBeDefined();
174
+ expect(signals.structural).toBeDefined();
175
+ expect(signals.context).toBeDefined();
176
+ expect(signals.lexical.hasArchitectureKeywords).toBe(true);
177
+ expect(signals.context.previousFailures).toBe(1);
178
+ });
179
+ });
180
+ });
181
+ // ============ Scoring System Tests ============
182
+ describe('Scoring System', () => {
183
+ describe('calculateComplexityScore', () => {
184
+ it('should score simple tasks low', () => {
185
+ const signals = {
186
+ lexical: {
187
+ wordCount: 10,
188
+ filePathCount: 0,
189
+ codeBlockCount: 0,
190
+ hasArchitectureKeywords: false,
191
+ hasDebuggingKeywords: false,
192
+ hasSimpleKeywords: true,
193
+ hasRiskKeywords: false,
194
+ questionDepth: 'what',
195
+ hasImplicitRequirements: false,
196
+ },
197
+ structural: {
198
+ estimatedSubtasks: 1,
199
+ crossFileDependencies: false,
200
+ hasTestRequirements: false,
201
+ domainSpecificity: 'generic',
202
+ requiresExternalKnowledge: false,
203
+ reversibility: 'easy',
204
+ impactScope: 'local',
205
+ },
206
+ context: {
207
+ previousFailures: 0,
208
+ conversationTurns: 0,
209
+ planComplexity: 0,
210
+ remainingTasks: 0,
211
+ agentChainDepth: 0,
212
+ },
213
+ };
214
+ const score = calculateComplexityScore(signals);
215
+ expect(score).toBeLessThan(4); // Should be LOW tier
216
+ });
217
+ it('should score complex tasks high', () => {
218
+ const signals = {
219
+ lexical: {
220
+ wordCount: 300,
221
+ filePathCount: 5,
222
+ codeBlockCount: 3,
223
+ hasArchitectureKeywords: true,
224
+ hasDebuggingKeywords: true,
225
+ hasSimpleKeywords: false,
226
+ hasRiskKeywords: true,
227
+ questionDepth: 'why',
228
+ hasImplicitRequirements: true,
229
+ },
230
+ structural: {
231
+ estimatedSubtasks: 8,
232
+ crossFileDependencies: true,
233
+ hasTestRequirements: true,
234
+ domainSpecificity: 'security',
235
+ requiresExternalKnowledge: true,
236
+ reversibility: 'difficult',
237
+ impactScope: 'system-wide',
238
+ },
239
+ context: {
240
+ previousFailures: 2,
241
+ conversationTurns: 10,
242
+ planComplexity: 10,
243
+ remainingTasks: 5,
244
+ agentChainDepth: 3,
245
+ },
246
+ };
247
+ const score = calculateComplexityScore(signals);
248
+ expect(score).toBeGreaterThanOrEqual(8); // Should be HIGH tier
249
+ });
250
+ it('should score medium complexity tasks appropriately', () => {
251
+ const signals = {
252
+ lexical: {
253
+ wordCount: 100,
254
+ filePathCount: 2,
255
+ codeBlockCount: 1,
256
+ hasArchitectureKeywords: false,
257
+ hasDebuggingKeywords: false,
258
+ hasSimpleKeywords: false,
259
+ hasRiskKeywords: false,
260
+ questionDepth: 'how',
261
+ hasImplicitRequirements: false,
262
+ },
263
+ structural: {
264
+ estimatedSubtasks: 3,
265
+ crossFileDependencies: false,
266
+ hasTestRequirements: true,
267
+ domainSpecificity: 'frontend',
268
+ requiresExternalKnowledge: false,
269
+ reversibility: 'moderate',
270
+ impactScope: 'module',
271
+ },
272
+ context: {
273
+ previousFailures: 0,
274
+ conversationTurns: 3,
275
+ planComplexity: 3,
276
+ remainingTasks: 2,
277
+ agentChainDepth: 1,
278
+ },
279
+ };
280
+ const score = calculateComplexityScore(signals);
281
+ expect(score).toBeGreaterThanOrEqual(4);
282
+ expect(score).toBeLessThan(8);
283
+ });
284
+ });
285
+ describe('scoreToTier', () => {
286
+ it('should map low scores to LOW tier', () => {
287
+ expect(scoreToTier(0)).toBe('LOW');
288
+ expect(scoreToTier(3)).toBe('LOW');
289
+ });
290
+ it('should map medium scores to MEDIUM tier', () => {
291
+ expect(scoreToTier(4)).toBe('MEDIUM');
292
+ expect(scoreToTier(7)).toBe('MEDIUM');
293
+ });
294
+ it('should map high scores to HIGH tier', () => {
295
+ expect(scoreToTier(8)).toBe('HIGH');
296
+ expect(scoreToTier(15)).toBe('HIGH');
297
+ expect(scoreToTier(100)).toBe('HIGH');
298
+ });
299
+ });
300
+ describe('calculateComplexityTier', () => {
301
+ it('should return correct tier for simple signals', () => {
302
+ const signals = {
303
+ lexical: {
304
+ wordCount: 10,
305
+ filePathCount: 0,
306
+ codeBlockCount: 0,
307
+ hasArchitectureKeywords: false,
308
+ hasDebuggingKeywords: false,
309
+ hasSimpleKeywords: true,
310
+ hasRiskKeywords: false,
311
+ questionDepth: 'none',
312
+ hasImplicitRequirements: false,
313
+ },
314
+ structural: {
315
+ estimatedSubtasks: 1,
316
+ crossFileDependencies: false,
317
+ hasTestRequirements: false,
318
+ domainSpecificity: 'generic',
319
+ requiresExternalKnowledge: false,
320
+ reversibility: 'easy',
321
+ impactScope: 'local',
322
+ },
323
+ context: {
324
+ previousFailures: 0,
325
+ conversationTurns: 0,
326
+ planComplexity: 0,
327
+ remainingTasks: 0,
328
+ agentChainDepth: 0,
329
+ },
330
+ };
331
+ expect(calculateComplexityTier(signals)).toBe('LOW');
332
+ });
333
+ });
334
+ describe('getScoreBreakdown', () => {
335
+ it('should provide detailed score breakdown', () => {
336
+ const signals = {
337
+ lexical: {
338
+ wordCount: 100,
339
+ filePathCount: 2,
340
+ codeBlockCount: 1,
341
+ hasArchitectureKeywords: true,
342
+ hasDebuggingKeywords: false,
343
+ hasSimpleKeywords: false,
344
+ hasRiskKeywords: false,
345
+ questionDepth: 'how',
346
+ hasImplicitRequirements: false,
347
+ },
348
+ structural: {
349
+ estimatedSubtasks: 3,
350
+ crossFileDependencies: true,
351
+ hasTestRequirements: false,
352
+ domainSpecificity: 'generic',
353
+ requiresExternalKnowledge: false,
354
+ reversibility: 'easy',
355
+ impactScope: 'module',
356
+ },
357
+ context: {
358
+ previousFailures: 0,
359
+ conversationTurns: 0,
360
+ planComplexity: 0,
361
+ remainingTasks: 0,
362
+ agentChainDepth: 0,
363
+ },
364
+ };
365
+ const breakdown = getScoreBreakdown(signals);
366
+ expect(breakdown).toHaveProperty('lexical');
367
+ expect(breakdown).toHaveProperty('structural');
368
+ expect(breakdown).toHaveProperty('context');
369
+ expect(breakdown).toHaveProperty('total');
370
+ expect(breakdown).toHaveProperty('tier');
371
+ expect(typeof breakdown.lexical).toBe('number');
372
+ expect(typeof breakdown.structural).toBe('number');
373
+ expect(typeof breakdown.context).toBe('number');
374
+ expect(breakdown.total).toBe(breakdown.lexical + breakdown.structural + breakdown.context);
375
+ });
376
+ });
377
+ describe('calculateConfidence', () => {
378
+ it('should calculate confidence for LOW tier', () => {
379
+ const confidence = calculateConfidence(1, 'LOW');
380
+ expect(confidence).toBeGreaterThan(0);
381
+ expect(confidence).toBeLessThanOrEqual(1);
382
+ });
383
+ it('should calculate confidence for MEDIUM tier', () => {
384
+ const confidence = calculateConfidence(5, 'MEDIUM');
385
+ expect(confidence).toBeGreaterThan(0);
386
+ expect(confidence).toBeLessThanOrEqual(1);
387
+ });
388
+ it('should calculate confidence for HIGH tier', () => {
389
+ const confidence = calculateConfidence(10, 'HIGH');
390
+ expect(confidence).toBeGreaterThan(0);
391
+ expect(confidence).toBeLessThanOrEqual(1);
392
+ });
393
+ it('should have higher confidence far from thresholds', () => {
394
+ const lowConfidence = calculateConfidence(4, 'MEDIUM'); // Right at threshold
395
+ const highConfidence = calculateConfidence(6, 'MEDIUM'); // Further from threshold
396
+ expect(highConfidence).toBeGreaterThanOrEqual(lowConfidence);
397
+ });
398
+ });
399
+ });
400
+ // ============ Routing Rules Tests ============
401
+ describe('Routing Rules', () => {
402
+ describe('evaluateRules', () => {
403
+ it('should evaluate explicit model rule', () => {
404
+ const context = {
405
+ taskPrompt: 'test',
406
+ explicitModel: 'opus',
407
+ };
408
+ const signals = extractAllSignals(context.taskPrompt, context);
409
+ const result = evaluateRules(context, signals);
410
+ expect(result.tier).toBe('EXPLICIT');
411
+ expect(result.ruleName).toBe('explicit-model-specified');
412
+ });
413
+ it('should evaluate orchestrator rule', () => {
414
+ const context = {
415
+ taskPrompt: 'test',
416
+ agentType: 'orchestrator-sisyphus',
417
+ };
418
+ const signals = extractAllSignals(context.taskPrompt, context);
419
+ const result = evaluateRules(context, signals);
420
+ expect(result.tier).toBe('HIGH');
421
+ expect(result.ruleName).toBe('orchestrator-fixed-opus');
422
+ });
423
+ it('should evaluate oracle complex debugging rule', () => {
424
+ const context = {
425
+ taskPrompt: 'Debug this issue and find the root cause',
426
+ agentType: 'oracle',
427
+ };
428
+ const signals = extractAllSignals(context.taskPrompt, context);
429
+ const result = evaluateRules(context, signals);
430
+ expect(result.tier).toBe('HIGH');
431
+ expect(result.ruleName).toBe('oracle-complex-debugging');
432
+ });
433
+ it('should evaluate oracle simple lookup rule', () => {
434
+ const context = {
435
+ taskPrompt: 'Find the file location',
436
+ agentType: 'oracle',
437
+ };
438
+ const signals = extractAllSignals(context.taskPrompt, context);
439
+ const result = evaluateRules(context, signals);
440
+ expect(result.tier).toBe('LOW');
441
+ expect(result.ruleName).toBe('oracle-simple-lookup');
442
+ });
443
+ it('should evaluate security domain rule', () => {
444
+ const context = {
445
+ taskPrompt: 'Fix the authentication vulnerability',
446
+ };
447
+ const signals = extractAllSignals(context.taskPrompt, context);
448
+ const result = evaluateRules(context, signals);
449
+ expect(result.tier).toBe('HIGH');
450
+ expect(result.ruleName).toBe('security-domain');
451
+ });
452
+ it('should evaluate simple search query rule', () => {
453
+ const context = {
454
+ taskPrompt: 'Find all TypeScript files',
455
+ };
456
+ const signals = extractAllSignals(context.taskPrompt, context);
457
+ const result = evaluateRules(context, signals);
458
+ // Could match simple-search-query or default-medium
459
+ expect(['LOW', 'MEDIUM']).toContain(result.tier);
460
+ });
461
+ it('should fall back to default rule', () => {
462
+ const context = {
463
+ taskPrompt: 'Some random task',
464
+ };
465
+ const signals = extractAllSignals(context.taskPrompt, context);
466
+ const result = evaluateRules(context, signals);
467
+ expect(result).toBeDefined();
468
+ expect(['LOW', 'MEDIUM', 'HIGH']).toContain(result.tier);
469
+ });
470
+ it('should respect rule priority order', () => {
471
+ const context = {
472
+ taskPrompt: 'test',
473
+ explicitModel: 'haiku',
474
+ agentType: 'orchestrator-sisyphus',
475
+ };
476
+ const signals = extractAllSignals(context.taskPrompt, context);
477
+ const result = evaluateRules(context, signals);
478
+ // Explicit model (priority 100) should win over orchestrator (priority 90)
479
+ expect(result.tier).toBe('EXPLICIT');
480
+ expect(result.ruleName).toBe('explicit-model-specified');
481
+ });
482
+ });
483
+ describe('getMatchingRules', () => {
484
+ it('should return all matching rules', () => {
485
+ const context = {
486
+ taskPrompt: 'Fix the authentication security vulnerability in production',
487
+ agentType: 'oracle',
488
+ };
489
+ const signals = extractAllSignals(context.taskPrompt, context);
490
+ const matches = getMatchingRules(context, signals);
491
+ expect(matches.length).toBeGreaterThan(0);
492
+ // Should match multiple rules
493
+ expect(matches.some(r => r.name === 'default-medium')).toBe(true);
494
+ });
495
+ });
496
+ describe('createRule', () => {
497
+ it('should create a custom rule', () => {
498
+ const rule = createRule('test-rule', (ctx) => ctx.taskPrompt.includes('test'), 'HIGH', 'Test reason', 50);
499
+ expect(rule.name).toBe('test-rule');
500
+ expect(rule.action.tier).toBe('HIGH');
501
+ expect(rule.action.reason).toBe('Test reason');
502
+ expect(rule.priority).toBe(50);
503
+ const context = { taskPrompt: 'test task' };
504
+ const signals = extractAllSignals(context.taskPrompt, context);
505
+ expect(rule.condition(context, signals)).toBe(true);
506
+ });
507
+ });
508
+ describe('mergeRules', () => {
509
+ it('should merge custom rules with defaults', () => {
510
+ const customRule = createRule('custom-rule', () => true, 'HIGH', 'Custom', 200);
511
+ const merged = mergeRules([customRule]);
512
+ expect(merged.length).toBeGreaterThan(DEFAULT_ROUTING_RULES.length);
513
+ expect(merged.some(r => r.name === 'custom-rule')).toBe(true);
514
+ expect(merged.some(r => r.name === 'default-medium')).toBe(true);
515
+ });
516
+ it('should override default rules with same name', () => {
517
+ const overrideRule = createRule('default-medium', () => true, 'HIGH', 'Override', 200);
518
+ const merged = mergeRules([overrideRule]);
519
+ const defaultMediumRules = merged.filter(r => r.name === 'default-medium');
520
+ expect(defaultMediumRules.length).toBe(1);
521
+ expect(defaultMediumRules[0].action.tier).toBe('HIGH');
522
+ });
523
+ });
524
+ });
525
+ // ============ Router Tests ============
526
+ describe('Router', () => {
527
+ describe('routeTask', () => {
528
+ it('should route simple task to LOW tier', () => {
529
+ const context = {
530
+ taskPrompt: 'Find the config file',
531
+ };
532
+ const decision = routeTask(context);
533
+ expect(decision.tier).toBe('LOW');
534
+ expect(decision.modelType).toBe('haiku');
535
+ expect(decision.model).toBe('claude-haiku-4-5-20251001');
536
+ });
537
+ it('should route complex task to HIGH tier', () => {
538
+ const context = {
539
+ taskPrompt: 'Refactor the entire architecture across multiple modules with security considerations',
540
+ };
541
+ const decision = routeTask(context);
542
+ expect(decision.tier).toBe('HIGH');
543
+ expect(decision.modelType).toBe('opus');
544
+ expect(decision.model).toBe('claude-opus-4-5-20251101');
545
+ });
546
+ it('should respect explicit model override', () => {
547
+ const context = {
548
+ taskPrompt: 'Complex architectural task',
549
+ explicitModel: 'haiku',
550
+ };
551
+ const decision = routeTask(context);
552
+ expect(decision.tier).toBe('LOW');
553
+ expect(decision.reasons[0]).toContain('Explicit model');
554
+ });
555
+ it('should respect agent overrides', () => {
556
+ const context = {
557
+ taskPrompt: 'test',
558
+ agentType: 'orchestrator-sisyphus',
559
+ };
560
+ const decision = routeTask(context, {
561
+ agentOverrides: {
562
+ 'orchestrator-sisyphus': { tier: 'HIGH', reason: 'Test override' },
563
+ },
564
+ });
565
+ expect(decision.tier).toBe('HIGH');
566
+ });
567
+ it('should handle disabled routing', () => {
568
+ const context = {
569
+ taskPrompt: 'test',
570
+ };
571
+ const decision = routeTask(context, { enabled: false });
572
+ expect(decision.reasons[0]).toContain('disabled');
573
+ });
574
+ it('should provide reasons for decision', () => {
575
+ const context = {
576
+ taskPrompt: 'Implement a new feature',
577
+ };
578
+ const decision = routeTask(context);
579
+ expect(decision.reasons).toBeDefined();
580
+ expect(decision.reasons.length).toBeGreaterThan(0);
581
+ });
582
+ it('should calculate confidence', () => {
583
+ const context = {
584
+ taskPrompt: 'Simple task',
585
+ };
586
+ const decision = routeTask(context);
587
+ expect(decision.confidence).toBeGreaterThan(0);
588
+ expect(decision.confidence).toBeLessThanOrEqual(1);
589
+ });
590
+ });
591
+ describe('escalateModel', () => {
592
+ it('should escalate from LOW to MEDIUM', () => {
593
+ expect(escalateModel('LOW')).toBe('MEDIUM');
594
+ });
595
+ it('should escalate from MEDIUM to HIGH', () => {
596
+ expect(escalateModel('MEDIUM')).toBe('HIGH');
597
+ });
598
+ it('should not escalate beyond HIGH', () => {
599
+ expect(escalateModel('HIGH')).toBe('HIGH');
600
+ });
601
+ });
602
+ describe('canEscalate', () => {
603
+ it('should return true for LOW tier', () => {
604
+ expect(canEscalate('LOW')).toBe(true);
605
+ });
606
+ it('should return true for MEDIUM tier', () => {
607
+ expect(canEscalate('MEDIUM')).toBe(true);
608
+ });
609
+ it('should return false for HIGH tier', () => {
610
+ expect(canEscalate('HIGH')).toBe(false);
611
+ });
612
+ });
613
+ describe('quickTierForAgent', () => {
614
+ it('should return HIGH for oracle', () => {
615
+ expect(quickTierForAgent('oracle')).toBe('HIGH');
616
+ });
617
+ it('should return HIGH for prometheus', () => {
618
+ expect(quickTierForAgent('prometheus')).toBe('HIGH');
619
+ });
620
+ it('should return LOW for explore', () => {
621
+ expect(quickTierForAgent('explore')).toBe('LOW');
622
+ });
623
+ it('should return MEDIUM for sisyphus-junior', () => {
624
+ expect(quickTierForAgent('sisyphus-junior')).toBe('MEDIUM');
625
+ });
626
+ it('should return null for unknown agent', () => {
627
+ expect(quickTierForAgent('unknown-agent')).toBeNull();
628
+ });
629
+ });
630
+ describe('isFixedTierAgent', () => {
631
+ it('should return true for orchestrator-sisyphus', () => {
632
+ expect(isFixedTierAgent('orchestrator-sisyphus')).toBe(true);
633
+ });
634
+ it('should return false for oracle', () => {
635
+ expect(isFixedTierAgent('oracle')).toBe(false);
636
+ });
637
+ it('should return false for sisyphus-junior', () => {
638
+ expect(isFixedTierAgent('sisyphus-junior')).toBe(false);
639
+ });
640
+ it('should return false for unknown agent', () => {
641
+ expect(isFixedTierAgent('unknown-agent')).toBe(false);
642
+ });
643
+ });
644
+ describe('getModelForTask', () => {
645
+ it('should return opus for orchestrator', () => {
646
+ const result = getModelForTask('orchestrator-sisyphus', 'test task');
647
+ expect(result.model).toBe('opus');
648
+ expect(result.tier).toBe('HIGH');
649
+ });
650
+ it('should return adaptive model for oracle with simple task', () => {
651
+ const result = getModelForTask('oracle', 'find the file');
652
+ expect(result.model).toBe('haiku');
653
+ expect(result.tier).toBe('LOW');
654
+ });
655
+ it('should return adaptive model for oracle with complex task', () => {
656
+ const result = getModelForTask('oracle', 'debug the root cause of this architecture issue');
657
+ expect(result.model).toBe('opus');
658
+ expect(result.tier).toBe('HIGH');
659
+ });
660
+ it('should return haiku for explore', () => {
661
+ const result = getModelForTask('explore', 'search for files');
662
+ expect(result.model).toBe('haiku');
663
+ expect(result.tier).toBe('LOW');
664
+ });
665
+ it('should provide reasoning', () => {
666
+ const result = getModelForTask('sisyphus-junior', 'implement feature');
667
+ expect(result.reason).toBeDefined();
668
+ expect(result.reason.length).toBeGreaterThan(0);
669
+ });
670
+ });
671
+ describe('analyzeTaskComplexity', () => {
672
+ it('should provide comprehensive analysis', () => {
673
+ const analysis = analyzeTaskComplexity('Refactor the architecture with security considerations');
674
+ expect(analysis.tier).toBeDefined();
675
+ expect(analysis.model).toBeDefined();
676
+ expect(analysis.analysis).toBeDefined();
677
+ expect(analysis.signals).toBeDefined();
678
+ expect(typeof analysis.analysis).toBe('string');
679
+ expect(analysis.analysis.length).toBeGreaterThan(0);
680
+ });
681
+ it('should detect signals in analysis', () => {
682
+ const analysis = analyzeTaskComplexity('Critical production security issue');
683
+ expect(analysis.signals.hasRiskKeywords).toBe(true);
684
+ });
685
+ it('should work with agent type', () => {
686
+ const analysis = analyzeTaskComplexity('test task', 'oracle');
687
+ expect(analysis).toBeDefined();
688
+ expect(analysis.tier).toBeDefined();
689
+ });
690
+ it('should provide signal details', () => {
691
+ const analysis = analyzeTaskComplexity('Fix bug in auth.ts and user.ts');
692
+ expect(analysis.signals.wordCount).toBeGreaterThan(0);
693
+ expect(analysis.signals.estimatedSubtasks).toBeGreaterThan(0);
694
+ });
695
+ });
696
+ });
697
+ // ============ Edge Cases and Integration Tests ============
698
+ describe('Edge Cases', () => {
699
+ it('should handle empty prompt', () => {
700
+ const context = {
701
+ taskPrompt: '',
702
+ };
703
+ const decision = routeTask(context);
704
+ expect(decision).toBeDefined();
705
+ expect(['LOW', 'MEDIUM', 'HIGH']).toContain(decision.tier);
706
+ });
707
+ it('should handle very long prompt', () => {
708
+ const longPrompt = 'word '.repeat(1000);
709
+ const context = {
710
+ taskPrompt: longPrompt,
711
+ };
712
+ const signals = extractLexicalSignals(longPrompt);
713
+ expect(signals.wordCount).toBeGreaterThan(500);
714
+ const decision = routeTask(context);
715
+ expect(decision).toBeDefined();
716
+ });
717
+ it('should handle special characters in prompt', () => {
718
+ const context = {
719
+ taskPrompt: 'Fix bug: $var = @array[0] && func() || die;',
720
+ };
721
+ const decision = routeTask(context);
722
+ expect(decision).toBeDefined();
723
+ });
724
+ it('should handle Unicode in prompt', () => {
725
+ const context = {
726
+ taskPrompt: 'Implement feature with 中文 and émojis 🚀',
727
+ };
728
+ const decision = routeTask(context);
729
+ expect(decision).toBeDefined();
730
+ });
731
+ it('should handle multiple conflicting signals', () => {
732
+ const context = {
733
+ taskPrompt: 'Simple find task but with critical production security architecture refactoring',
734
+ };
735
+ const signals = extractAllSignals(context.taskPrompt, context);
736
+ expect(signals.lexical.hasSimpleKeywords).toBe(true);
737
+ expect(signals.lexical.hasArchitectureKeywords).toBe(true);
738
+ expect(signals.lexical.hasRiskKeywords).toBe(true);
739
+ const decision = routeTask(context);
740
+ // Should prioritize high-complexity signals
741
+ expect(decision.tier).toBe('HIGH');
742
+ });
743
+ it('should handle context with maximum values', () => {
744
+ const context = {
745
+ taskPrompt: 'test',
746
+ previousFailures: 100,
747
+ conversationTurns: 1000,
748
+ planTasks: 500,
749
+ remainingTasks: 400,
750
+ agentChainDepth: 50,
751
+ };
752
+ const signals = extractContextSignals(context);
753
+ expect(signals.previousFailures).toBe(100);
754
+ const decision = routeTask(context);
755
+ expect(decision).toBeDefined();
756
+ });
757
+ });
758
+ describe('Integration Scenarios', () => {
759
+ it('should handle real-world simple search', () => {
760
+ const context = {
761
+ taskPrompt: 'Find all TypeScript files in the src directory',
762
+ agentType: 'explore',
763
+ };
764
+ const decision = routeTask(context);
765
+ expect(decision.tier).toBe('LOW');
766
+ expect(decision.modelType).toBe('haiku');
767
+ });
768
+ it('should handle real-world debugging task', () => {
769
+ const context = {
770
+ taskPrompt: 'Investigate why the authentication system is failing in production. Need root cause analysis.',
771
+ agentType: 'oracle',
772
+ };
773
+ const decision = routeTask(context);
774
+ expect(decision.tier).toBe('HIGH');
775
+ expect(decision.modelType).toBe('opus');
776
+ });
777
+ it('should handle real-world refactoring task', () => {
778
+ const context = {
779
+ taskPrompt: 'Refactor the API layer to separate concerns and improve maintainability across auth, user, and admin modules',
780
+ agentType: 'sisyphus-junior',
781
+ };
782
+ const decision = routeTask(context);
783
+ // Moderate refactoring without explicit high-complexity signals → MEDIUM
784
+ expect(decision.tier).toBe('MEDIUM');
785
+ });
786
+ it('should handle real-world simple change', () => {
787
+ const context = {
788
+ taskPrompt: 'Add a console.log statement in utils.ts',
789
+ agentType: 'sisyphus-junior',
790
+ };
791
+ const decision = routeTask(context);
792
+ expect(decision.tier).toBe('LOW');
793
+ });
794
+ it('should handle strategic planning task', () => {
795
+ const context = {
796
+ taskPrompt: 'Create a comprehensive strategic plan for refactoring the entire system architecture to migrate our monolith to microservices across all domains with minimal production downtime',
797
+ agentType: 'prometheus',
798
+ };
799
+ const decision = routeTask(context);
800
+ // Strategic planning with system-wide architecture keywords → HIGH
801
+ expect(decision.tier).toBe('HIGH');
802
+ });
803
+ it('should escalate on previous failures', () => {
804
+ const context = {
805
+ taskPrompt: 'Simple task that keeps failing',
806
+ previousFailures: 3,
807
+ };
808
+ const _decision = routeTask(context);
809
+ // Previous failures should increase complexity score
810
+ const signals = extractContextSignals(context);
811
+ expect(signals.previousFailures).toBe(3);
812
+ });
813
+ });
814
+ //# sourceMappingURL=model-routing.test.js.map