@pennyfarthing/cyclist 10.3.1 → 11.0.0-alpha.0

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 (271) hide show
  1. package/dist/api/agent-load.d.ts +1 -2
  2. package/dist/api/agent-load.d.ts.map +1 -1
  3. package/dist/api/agent-load.js +2 -123
  4. package/dist/api/agent-load.js.map +1 -1
  5. package/dist/api/audit-log.d.ts +1 -17
  6. package/dist/api/audit-log.d.ts.map +1 -1
  7. package/dist/api/audit-log.js +2 -162
  8. package/dist/api/audit-log.js.map +1 -1
  9. package/dist/api/background-tasks.d.ts +1 -26
  10. package/dist/api/background-tasks.d.ts.map +1 -1
  11. package/dist/api/background-tasks.js +2 -55
  12. package/dist/api/background-tasks.js.map +1 -1
  13. package/dist/api/bell.d.ts +1 -18
  14. package/dist/api/bell.d.ts.map +1 -1
  15. package/dist/api/bell.js +2 -33
  16. package/dist/api/bell.js.map +1 -1
  17. package/dist/api/code-markers.d.ts +1 -8
  18. package/dist/api/code-markers.d.ts.map +1 -1
  19. package/dist/api/code-markers.js +2 -61
  20. package/dist/api/code-markers.js.map +1 -1
  21. package/dist/api/complexity.d.ts +1 -2
  22. package/dist/api/complexity.d.ts.map +1 -1
  23. package/dist/api/complexity.js +2 -46
  24. package/dist/api/complexity.js.map +1 -1
  25. package/dist/api/context.d.ts +1 -37
  26. package/dist/api/context.d.ts.map +1 -1
  27. package/dist/api/context.js +2 -143
  28. package/dist/api/context.js.map +1 -1
  29. package/dist/api/dead-code.d.ts +1 -2
  30. package/dist/api/dead-code.d.ts.map +1 -1
  31. package/dist/api/dead-code.js +2 -69
  32. package/dist/api/dead-code.js.map +1 -1
  33. package/dist/api/dependencies.d.ts +1 -2
  34. package/dist/api/dependencies.d.ts.map +1 -1
  35. package/dist/api/dependencies.js +2 -42
  36. package/dist/api/dependencies.js.map +1 -1
  37. package/dist/api/evaluation.d.ts +1 -19
  38. package/dist/api/evaluation.d.ts.map +1 -1
  39. package/dist/api/evaluation.js +2 -127
  40. package/dist/api/evaluation.js.map +1 -1
  41. package/dist/api/file-browser.d.ts +1 -8
  42. package/dist/api/file-browser.d.ts.map +1 -1
  43. package/dist/api/file-browser.js +2 -114
  44. package/dist/api/file-browser.js.map +1 -1
  45. package/dist/api/git.d.ts +1 -46
  46. package/dist/api/git.d.ts.map +1 -1
  47. package/dist/api/git.js +2 -354
  48. package/dist/api/git.js.map +1 -1
  49. package/dist/api/health-score.d.ts +1 -2
  50. package/dist/api/health-score.d.ts.map +1 -1
  51. package/dist/api/health-score.js +2 -46
  52. package/dist/api/health-score.js.map +1 -1
  53. package/dist/api/hook-request.d.ts +1 -40
  54. package/dist/api/hook-request.d.ts.map +1 -1
  55. package/dist/api/hook-request.js +2 -277
  56. package/dist/api/hook-request.js.map +1 -1
  57. package/dist/api/hotspots.d.ts +1 -2
  58. package/dist/api/hotspots.d.ts.map +1 -1
  59. package/dist/api/hotspots.js +2 -61
  60. package/dist/api/hotspots.js.map +1 -1
  61. package/dist/api/identity.d.ts +1 -16
  62. package/dist/api/identity.d.ts.map +1 -1
  63. package/dist/api/identity.js +2 -78
  64. package/dist/api/identity.js.map +1 -1
  65. package/dist/api/index.d.ts +1 -34
  66. package/dist/api/index.d.ts.map +1 -1
  67. package/dist/api/index.js +2 -44
  68. package/dist/api/index.js.map +1 -1
  69. package/dist/api/mode.d.ts +1 -22
  70. package/dist/api/mode.d.ts.map +1 -1
  71. package/dist/api/mode.js +2 -37
  72. package/dist/api/mode.js.map +1 -1
  73. package/dist/api/otlp.d.ts +1 -2
  74. package/dist/api/otlp.d.ts.map +1 -1
  75. package/dist/api/otlp.js +2 -46
  76. package/dist/api/otlp.js.map +1 -1
  77. package/dist/api/permissions.d.ts +1 -15
  78. package/dist/api/permissions.d.ts.map +1 -1
  79. package/dist/api/permissions.js +2 -66
  80. package/dist/api/permissions.js.map +1 -1
  81. package/dist/api/persona.d.ts +1 -8
  82. package/dist/api/persona.d.ts.map +1 -1
  83. package/dist/api/persona.js +2 -67
  84. package/dist/api/persona.js.map +1 -1
  85. package/dist/api/portrait.d.ts +1 -5
  86. package/dist/api/portrait.d.ts.map +1 -1
  87. package/dist/api/portrait.js +2 -27
  88. package/dist/api/portrait.js.map +1 -1
  89. package/dist/api/settings.d.ts +1 -53
  90. package/dist/api/settings.d.ts.map +1 -1
  91. package/dist/api/settings.js +2 -464
  92. package/dist/api/settings.js.map +1 -1
  93. package/dist/api/spans.d.ts +1 -16
  94. package/dist/api/spans.d.ts.map +1 -1
  95. package/dist/api/spans.js +2 -244
  96. package/dist/api/spans.js.map +1 -1
  97. package/dist/api/stats.d.ts +1 -12
  98. package/dist/api/stats.d.ts.map +1 -1
  99. package/dist/api/stats.js +2 -84
  100. package/dist/api/stats.js.map +1 -1
  101. package/dist/api/story.d.ts +1 -2
  102. package/dist/api/story.d.ts.map +1 -1
  103. package/dist/api/story.js +2 -14
  104. package/dist/api/story.js.map +1 -1
  105. package/dist/api/telemetry.d.ts +1 -18
  106. package/dist/api/telemetry.d.ts.map +1 -1
  107. package/dist/api/telemetry.js +2 -164
  108. package/dist/api/telemetry.js.map +1 -1
  109. package/dist/api/theme-agents.d.ts +1 -60
  110. package/dist/api/theme-agents.d.ts.map +1 -1
  111. package/dist/api/theme-agents.js +2 -213
  112. package/dist/api/theme-agents.js.map +1 -1
  113. package/dist/api/todos.d.ts +1 -32
  114. package/dist/api/todos.d.ts.map +1 -1
  115. package/dist/api/todos.js +2 -43
  116. package/dist/api/todos.js.map +1 -1
  117. package/dist/api/token-stats.d.ts +1 -7
  118. package/dist/api/token-stats.d.ts.map +1 -1
  119. package/dist/api/token-stats.js +2 -35
  120. package/dist/api/token-stats.js.map +1 -1
  121. package/dist/api/welcome.d.ts +1 -21
  122. package/dist/api/welcome.d.ts.map +1 -1
  123. package/dist/api/welcome.js +2 -34
  124. package/dist/api/welcome.js.map +1 -1
  125. package/dist/env.d.ts +6 -0
  126. package/dist/env.d.ts.map +1 -0
  127. package/dist/env.js +10 -0
  128. package/dist/env.js.map +1 -0
  129. package/dist/focus.d.ts +53 -0
  130. package/dist/focus.d.ts.map +1 -0
  131. package/dist/focus.js +122 -0
  132. package/dist/focus.js.map +1 -0
  133. package/dist/menu-builder.d.ts.map +1 -1
  134. package/dist/menu-builder.js +0 -1
  135. package/dist/menu-builder.js.map +1 -1
  136. package/dist/public/css/react.css +1 -1
  137. package/dist/public/js/react/react.js +51 -59
  138. package/dist/server.d.ts +16 -85
  139. package/dist/server.d.ts.map +1 -1
  140. package/dist/server.js +38 -409
  141. package/dist/server.js.map +1 -1
  142. package/dist/sprint-data.d.ts +1 -1
  143. package/dist/sprint-data.d.ts.map +1 -1
  144. package/dist/sprint-data.js +29 -8
  145. package/dist/sprint-data.js.map +1 -1
  146. package/dist/websocket.d.ts +2 -0
  147. package/dist/websocket.d.ts.map +1 -1
  148. package/dist/websocket.js +45 -78
  149. package/dist/websocket.js.map +1 -1
  150. package/package.json +33 -35
  151. package/portraits/hogans-heroes/large/burkhalter-35312.png +0 -0
  152. package/portraits/hogans-heroes/large/carter-34352.png +0 -0
  153. package/portraits/hogans-heroes/large/hochstetter-45314.png +0 -0
  154. package/portraits/hogans-heroes/large/hogan-44541.png +0 -0
  155. package/portraits/hogans-heroes/large/kinch-35241.png +0 -0
  156. package/portraits/hogans-heroes/large/klink-23434.png +0 -0
  157. package/portraits/hogans-heroes/large/lebeau-45443.png +0 -0
  158. package/portraits/hogans-heroes/large/marya-53543.png +0 -0
  159. package/portraits/hogans-heroes/large/newkirk-54432.png +0 -0
  160. package/portraits/hogans-heroes/large/schultz-42453.png +0 -0
  161. package/portraits/hogans-heroes/large/underground-55131.png +0 -0
  162. package/portraits/hogans-heroes/medium/burkhalter-35312.png +0 -0
  163. package/portraits/hogans-heroes/medium/carter-34352.png +0 -0
  164. package/portraits/hogans-heroes/medium/hochstetter-45314.png +0 -0
  165. package/portraits/hogans-heroes/medium/hogan-44541.png +0 -0
  166. package/portraits/hogans-heroes/medium/kinch-35241.png +0 -0
  167. package/portraits/hogans-heroes/medium/klink-23434.png +0 -0
  168. package/portraits/hogans-heroes/medium/lebeau-45443.png +0 -0
  169. package/portraits/hogans-heroes/medium/marya-53543.png +0 -0
  170. package/portraits/hogans-heroes/medium/newkirk-54432.png +0 -0
  171. package/portraits/hogans-heroes/medium/schultz-42453.png +0 -0
  172. package/portraits/hogans-heroes/medium/underground-55131.png +0 -0
  173. package/portraits/monty-python/large/announcer-44441.png +0 -0
  174. package/portraits/monty-python/large/arguer-35412.png +0 -0
  175. package/portraits/monty-python/large/bicycle-repair-man-35241.png +0 -0
  176. package/portraits/monty-python/large/colonel-35423.png +0 -0
  177. package/portraits/monty-python/large/counsellor-45341.png +0 -0
  178. package/portraits/monty-python/large/gumbys-23524.png +0 -0
  179. package/portraits/monty-python/large/nudge-43533.png +0 -0
  180. package/portraits/monty-python/large/praline-45413.png +0 -0
  181. package/portraits/monty-python/large/silly-walks-55322.png +0 -0
  182. package/portraits/monty-python/large/wensleydale-54451.png +0 -0
  183. package/portraits/monty-python/large/xim-nez-43534.png +0 -0
  184. package/portraits/monty-python/medium/announcer-44441.png +0 -0
  185. package/portraits/monty-python/medium/arguer-35412.png +0 -0
  186. package/portraits/monty-python/medium/bicycle-repair-man-35241.png +0 -0
  187. package/portraits/monty-python/medium/colonel-35423.png +0 -0
  188. package/portraits/monty-python/medium/counsellor-45341.png +0 -0
  189. package/portraits/monty-python/medium/gumbys-23524.png +0 -0
  190. package/portraits/monty-python/medium/nudge-43533.png +0 -0
  191. package/portraits/monty-python/medium/praline-45413.png +0 -0
  192. package/portraits/monty-python/medium/silly-walks-55322.png +0 -0
  193. package/portraits/monty-python/medium/wensleydale-54451.png +0 -0
  194. package/portraits/monty-python/medium/xim-nez-43534.png +0 -0
  195. package/portraits/stephen-king/large/andy-55231.png +0 -0
  196. package/portraits/stephen-king/large/christine-25112.png +0 -0
  197. package/portraits/stephen-king/large/danny-53243.png +0 -0
  198. package/portraits/stephen-king/large/flagg-55311.png +0 -0
  199. package/portraits/stephen-king/large/gaunt-54421.png +0 -0
  200. package/portraits/stephen-king/large/jack-44224.png +0 -0
  201. package/portraits/stephen-king/large/johnny-44353.png +0 -0
  202. package/portraits/stephen-king/large/margaret-15415.png +0 -0
  203. package/portraits/stephen-king/large/paul-45233.png +0 -0
  204. package/portraits/stephen-king/large/pennywise-54411.png +0 -0
  205. package/portraits/stephen-king/large/roland-35121.png +0 -0
  206. package/portraits/stephen-king/medium/andy-55231.png +0 -0
  207. package/portraits/stephen-king/medium/christine-25112.png +0 -0
  208. package/portraits/stephen-king/medium/danny-53243.png +0 -0
  209. package/portraits/stephen-king/medium/flagg-55311.png +0 -0
  210. package/portraits/stephen-king/medium/gaunt-54421.png +0 -0
  211. package/portraits/stephen-king/medium/jack-44224.png +0 -0
  212. package/portraits/stephen-king/medium/johnny-44353.png +0 -0
  213. package/portraits/stephen-king/medium/margaret-15415.png +0 -0
  214. package/portraits/stephen-king/medium/paul-45233.png +0 -0
  215. package/portraits/stephen-king/medium/pennywise-54411.png +0 -0
  216. package/portraits/stephen-king/medium/roland-35121.png +0 -0
  217. package/src/public/App.tsx +21 -5
  218. package/src/public/components/BikeRackIndex.tsx +0 -1
  219. package/src/public/components/BikeRackWorkspace.tsx +86 -11
  220. package/src/public/components/DockviewWorkspace.tsx +19 -8
  221. package/src/public/components/StandalonePanel.tsx +1 -3
  222. package/src/public/components/panel-registry.ts +3 -1
  223. package/src/public/components/panels/AuditLogPanel.tsx +28 -4
  224. package/src/public/components/panels/GitPanel.tsx +1 -20
  225. package/src/public/components/panels/SettingsPanel.tsx +0 -1
  226. package/src/public/components/panels/SprintPanel.tsx +32 -1
  227. package/src/public/components/panels/index.ts +0 -2
  228. package/src/public/hooks/useFocusPanel.ts +137 -0
  229. package/src/public/hooks/useLayoutPersistence.ts +8 -5
  230. package/src/public/styles/dockview-theme.css +1 -84
  231. package/src/public/styles/tailwind.css +27 -32
  232. package/src/public/utils/slash-commands.ts +122 -98
  233. package/LICENSE +0 -14
  234. package/dist/hooks/cyclist-pretooluse-hook.d.ts +0 -60
  235. package/dist/hooks/cyclist-pretooluse-hook.d.ts.map +0 -1
  236. package/dist/hooks/cyclist-pretooluse-hook.js +0 -57
  237. package/dist/hooks/cyclist-pretooluse-hook.js.map +0 -1
  238. package/dist/hooks/pretooluse-hook.d.ts +0 -89
  239. package/dist/hooks/pretooluse-hook.d.ts.map +0 -1
  240. package/dist/hooks/pretooluse-hook.js +0 -235
  241. package/dist/hooks/pretooluse-hook.js.map +0 -1
  242. package/dist/notification-sound.d.ts +0 -59
  243. package/dist/notification-sound.d.ts.map +0 -1
  244. package/dist/notification-sound.js +0 -219
  245. package/dist/notification-sound.js.map +0 -1
  246. package/dist/plugin-loader.test.d.ts +0 -17
  247. package/dist/plugin-loader.test.d.ts.map +0 -1
  248. package/dist/plugin-loader.test.js +0 -407
  249. package/dist/plugin-loader.test.js.map +0 -1
  250. package/portraits/star-trek-tng/large/beverly-44352.png +0 -0
  251. package/portraits/star-trek-tng/large/data-55241.png +0 -0
  252. package/portraits/star-trek-tng/large/deanna-43353.png +0 -0
  253. package/portraits/star-trek-tng/large/geordi-54342.png +0 -0
  254. package/portraits/star-trek-tng/large/jean-luc-45342.png +0 -0
  255. package/portraits/star-trek-tng/large/kathryn-45332.png +0 -0
  256. package/portraits/star-trek-tng/large/miles-35342.png +0 -0
  257. package/portraits/star-trek-tng/large/q-53521.png +0 -0
  258. package/portraits/star-trek-tng/large/spock-45231.png +0 -0
  259. package/portraits/star-trek-tng/large/troi-44352.png +0 -0
  260. package/portraits/star-trek-tng/medium/beverly-44352.png +0 -0
  261. package/portraits/star-trek-tng/medium/data-55241.png +0 -0
  262. package/portraits/star-trek-tng/medium/deanna-43353.png +0 -0
  263. package/portraits/star-trek-tng/medium/geordi-54342.png +0 -0
  264. package/portraits/star-trek-tng/medium/jean-luc-45342.png +0 -0
  265. package/portraits/star-trek-tng/medium/kathryn-45332.png +0 -0
  266. package/portraits/star-trek-tng/medium/miles-35342.png +0 -0
  267. package/portraits/star-trek-tng/medium/q-53521.png +0 -0
  268. package/portraits/star-trek-tng/medium/spock-45231.png +0 -0
  269. package/portraits/star-trek-tng/medium/troi-44352.png +0 -0
  270. package/src/public/components/panels/TTYPanel.tsx +0 -299
  271. package/src/public/types/electron.d.ts +0 -18
@@ -1,407 +0,0 @@
1
- /**
2
- * Tests for Story 93-6: Plugin Router Loader for Cyclist
3
- *
4
- * Tests the dynamic discovery and mounting of API routers from installed
5
- * @pennyfarthing/* plugin packages. The loader uses the plugin discovery
6
- * system (93-3) to find plugins and mount their Express routers.
7
- *
8
- * Test categories:
9
- * 1. initPluginRouters() - Core loading behavior
10
- * 2. Plugin with API router - Benchmark plugin integration
11
- * 3. Graceful degradation - Missing packages, failed imports
12
- * 4. Cyclist starts without plugins - Empty state
13
- *
14
- * Run with: cd packages/cyclist && pnpm test
15
- */
16
- import { describe, it, expect, vi, beforeEach } from 'vitest';
17
- import express from 'express';
18
- import { initPluginRouters } from './plugin-loader.js';
19
- // Mock @pennyfarthing/core plugin discovery
20
- vi.mock('@pennyfarthing/core', async () => {
21
- const actual = await vi.importActual('@pennyfarthing/core');
22
- return {
23
- ...actual,
24
- discoverPlugins: vi.fn(),
25
- getPluginRouters: vi.fn(),
26
- };
27
- });
28
- // Get mocked functions for test control
29
- import { discoverPlugins, getPluginRouters } from '@pennyfarthing/core';
30
- const mockDiscoverPlugins = vi.mocked(discoverPlugins);
31
- const mockGetPluginRouters = vi.mocked(getPluginRouters);
32
- // Helper: create a fake Express Router
33
- function createFakeRouter() {
34
- const router = express.Router();
35
- router.get('/test', (_req, res) => res.json({ ok: true }));
36
- return router;
37
- }
38
- describe('initPluginRouters()', () => {
39
- let app;
40
- beforeEach(() => {
41
- app = express();
42
- vi.clearAllMocks();
43
- });
44
- it('should return PluginLoadResult with correct shape', async () => {
45
- mockDiscoverPlugins.mockReturnValue([]);
46
- mockGetPluginRouters.mockReturnValue([]);
47
- const result = await initPluginRouters(app, '/fake/project');
48
- expect(result).toHaveProperty('discovered');
49
- expect(result).toHaveProperty('loaded');
50
- expect(result).toHaveProperty('failed');
51
- expect(result).toHaveProperty('routers');
52
- expect(typeof result.discovered).toBe('number');
53
- expect(typeof result.loaded).toBe('number');
54
- expect(typeof result.failed).toBe('number');
55
- expect(Array.isArray(result.routers)).toBe(true);
56
- });
57
- it('should report zero when no plugins are discovered', async () => {
58
- mockDiscoverPlugins.mockReturnValue([]);
59
- mockGetPluginRouters.mockReturnValue([]);
60
- const result = await initPluginRouters(app, '/fake/project');
61
- expect(result.discovered).toBe(0);
62
- expect(result.loaded).toBe(0);
63
- expect(result.failed).toBe(0);
64
- expect(result.routers).toHaveLength(0);
65
- });
66
- it('should call discoverPlugins with the project root', async () => {
67
- mockDiscoverPlugins.mockReturnValue([]);
68
- mockGetPluginRouters.mockReturnValue([]);
69
- await initPluginRouters(app, '/my/project');
70
- expect(mockDiscoverPlugins).toHaveBeenCalledWith('/my/project');
71
- });
72
- it('should pass discovered plugins to getPluginRouters', async () => {
73
- const fakePlugins = [
74
- {
75
- name: '@pennyfarthing/benchmark',
76
- path: '/node_modules/@pennyfarthing/benchmark',
77
- manifest: { commands: 'commands/', skills: 'skills/' },
78
- },
79
- ];
80
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
81
- mockGetPluginRouters.mockReturnValue([]);
82
- await initPluginRouters(app, '/fake/project');
83
- expect(mockGetPluginRouters).toHaveBeenCalledWith(fakePlugins);
84
- });
85
- it('should report discovered count matching number of plugins', async () => {
86
- const fakePlugins = [
87
- {
88
- name: '@pennyfarthing/benchmark',
89
- path: '/node_modules/@pennyfarthing/benchmark',
90
- manifest: { commands: 'commands/' },
91
- },
92
- {
93
- name: '@pennyfarthing/analytics',
94
- path: '/node_modules/@pennyfarthing/analytics',
95
- manifest: { commands: 'commands/' },
96
- },
97
- ];
98
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
99
- mockGetPluginRouters.mockReturnValue([]);
100
- const result = await initPluginRouters(app, '/fake/project');
101
- expect(result.discovered).toBe(2);
102
- });
103
- });
104
- describe('Plugin with API router', () => {
105
- let app;
106
- beforeEach(() => {
107
- app = express();
108
- vi.clearAllMocks();
109
- });
110
- it('should dynamically import and mount a plugin router', async () => {
111
- const fakePlugins = [
112
- {
113
- name: '@pennyfarthing/benchmark',
114
- path: '/node_modules/@pennyfarthing/benchmark',
115
- manifest: {
116
- commands: 'commands/',
117
- api: {
118
- path: '/api/benchmark',
119
- module: './dist/api/benchmark.js',
120
- export: 'createBenchmarkRouter',
121
- },
122
- },
123
- },
124
- ];
125
- const fakeRouters = [
126
- {
127
- mountPath: '/api/benchmark',
128
- modulePath: '/node_modules/@pennyfarthing/benchmark/dist/api/benchmark.js',
129
- exportName: 'createBenchmarkRouter',
130
- plugin: '@pennyfarthing/benchmark',
131
- },
132
- ];
133
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
134
- mockGetPluginRouters.mockReturnValue(fakeRouters);
135
- // Mock the dynamic import to return a module with the router factory
136
- const fakeRouter = createFakeRouter();
137
- vi.stubGlobal('import', undefined); // Clear any previous stubs
138
- // We need to mock the dynamic import that initPluginRouters will use
139
- // The implementation should use: const mod = await import(modulePath)
140
- // We mock it via vi.mock for the specific module path
141
- const originalImport = globalThis.import;
142
- // @ts-expect-error - mocking dynamic import
143
- globalThis.__pluginImportMock = vi.fn().mockResolvedValue({
144
- createBenchmarkRouter: () => fakeRouter,
145
- });
146
- const result = await initPluginRouters(app, '/fake/project');
147
- expect(result.loaded).toBe(1);
148
- expect(result.failed).toBe(0);
149
- expect(result.routers).toHaveLength(1);
150
- expect(result.routers[0]).toEqual(expect.objectContaining({
151
- mountPath: '/api/benchmark',
152
- plugin: '@pennyfarthing/benchmark',
153
- success: true,
154
- }));
155
- });
156
- it('should mount router at the declared mount path', async () => {
157
- const fakePlugins = [
158
- {
159
- name: '@pennyfarthing/benchmark',
160
- path: '/node_modules/@pennyfarthing/benchmark',
161
- manifest: {
162
- api: {
163
- path: '/api/benchmark',
164
- module: './dist/api/benchmark.js',
165
- export: 'createBenchmarkRouter',
166
- },
167
- },
168
- },
169
- ];
170
- const fakeRouters = [
171
- {
172
- mountPath: '/api/benchmark',
173
- modulePath: '/node_modules/@pennyfarthing/benchmark/dist/api/benchmark.js',
174
- exportName: 'createBenchmarkRouter',
175
- plugin: '@pennyfarthing/benchmark',
176
- },
177
- ];
178
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
179
- mockGetPluginRouters.mockReturnValue(fakeRouters);
180
- // Spy on app.use to verify the mount path
181
- const useSpy = vi.spyOn(app, 'use');
182
- const result = await initPluginRouters(app, '/fake/project');
183
- // Verify app.use was called with the correct mount path
184
- if (result.loaded > 0) {
185
- const mountCalls = useSpy.mock.calls.filter((call) => call[0] === '/api/benchmark');
186
- expect(mountCalls.length).toBeGreaterThan(0);
187
- }
188
- });
189
- it('should pass getProjectDir to router factory if it accepts arguments', async () => {
190
- // Some routers take a getProjectDir function as argument
191
- // The plugin loader should detect this and pass it
192
- const fakePlugins = [
193
- {
194
- name: '@pennyfarthing/benchmark',
195
- path: '/node_modules/@pennyfarthing/benchmark',
196
- manifest: {
197
- api: {
198
- path: '/api/benchmark',
199
- module: './dist/api/benchmark.js',
200
- export: 'createBenchmarkRouter',
201
- },
202
- },
203
- },
204
- ];
205
- const fakeRouters = [
206
- {
207
- mountPath: '/api/benchmark',
208
- modulePath: '/node_modules/@pennyfarthing/benchmark/dist/api/benchmark.js',
209
- exportName: 'createBenchmarkRouter',
210
- plugin: '@pennyfarthing/benchmark',
211
- },
212
- ];
213
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
214
- mockGetPluginRouters.mockReturnValue(fakeRouters);
215
- // The result should include the mounted router
216
- const result = await initPluginRouters(app, '/fake/project');
217
- // If loaded successfully, the factory was called
218
- expect(result).toBeDefined();
219
- });
220
- });
221
- describe('Graceful degradation', () => {
222
- let app;
223
- beforeEach(() => {
224
- app = express();
225
- vi.clearAllMocks();
226
- });
227
- it('should handle failed dynamic import gracefully', async () => {
228
- const fakePlugins = [
229
- {
230
- name: '@pennyfarthing/broken',
231
- path: '/node_modules/@pennyfarthing/broken',
232
- manifest: {
233
- api: {
234
- path: '/api/broken',
235
- module: './dist/api/broken.js',
236
- export: 'createBrokenRouter',
237
- },
238
- },
239
- },
240
- ];
241
- const fakeRouters = [
242
- {
243
- mountPath: '/api/broken',
244
- modulePath: '/node_modules/@pennyfarthing/broken/dist/api/broken.js',
245
- exportName: 'createBrokenRouter',
246
- plugin: '@pennyfarthing/broken',
247
- },
248
- ];
249
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
250
- mockGetPluginRouters.mockReturnValue(fakeRouters);
251
- // The module path doesn't exist, so dynamic import will fail
252
- const result = await initPluginRouters(app, '/fake/project');
253
- // Should NOT throw — graceful degradation
254
- expect(result.loaded).toBe(0);
255
- expect(result.failed).toBe(1);
256
- expect(result.routers[0]).toEqual(expect.objectContaining({
257
- mountPath: '/api/broken',
258
- plugin: '@pennyfarthing/broken',
259
- success: false,
260
- }));
261
- expect(result.routers[0].error).toBeDefined();
262
- });
263
- it('should handle missing export name in module gracefully', async () => {
264
- const fakePlugins = [
265
- {
266
- name: '@pennyfarthing/noexport',
267
- path: '/node_modules/@pennyfarthing/noexport',
268
- manifest: {
269
- api: {
270
- path: '/api/noexport',
271
- module: './dist/api/noexport.js',
272
- export: 'createNonexistentRouter',
273
- },
274
- },
275
- },
276
- ];
277
- const fakeRouters = [
278
- {
279
- mountPath: '/api/noexport',
280
- modulePath: '/node_modules/@pennyfarthing/noexport/dist/api/noexport.js',
281
- exportName: 'createNonexistentRouter',
282
- plugin: '@pennyfarthing/noexport',
283
- },
284
- ];
285
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
286
- mockGetPluginRouters.mockReturnValue(fakeRouters);
287
- const result = await initPluginRouters(app, '/fake/project');
288
- // Should fail gracefully when the export doesn't exist
289
- expect(result.failed).toBeGreaterThanOrEqual(1);
290
- const routerResult = result.routers.find((r) => r.plugin === '@pennyfarthing/noexport');
291
- expect(routerResult?.success).toBe(false);
292
- });
293
- it('should continue loading other plugins when one fails', async () => {
294
- const fakePlugins = [
295
- {
296
- name: '@pennyfarthing/broken',
297
- path: '/node_modules/@pennyfarthing/broken',
298
- manifest: {
299
- api: {
300
- path: '/api/broken',
301
- module: './dist/api/broken.js',
302
- export: 'createBrokenRouter',
303
- },
304
- },
305
- },
306
- {
307
- name: '@pennyfarthing/good',
308
- path: '/node_modules/@pennyfarthing/good',
309
- manifest: {
310
- api: {
311
- path: '/api/good',
312
- module: './dist/api/good.js',
313
- export: 'createGoodRouter',
314
- },
315
- },
316
- },
317
- ];
318
- const fakeRouters = [
319
- {
320
- mountPath: '/api/broken',
321
- modulePath: '/node_modules/@pennyfarthing/broken/dist/api/broken.js',
322
- exportName: 'createBrokenRouter',
323
- plugin: '@pennyfarthing/broken',
324
- },
325
- {
326
- mountPath: '/api/good',
327
- modulePath: '/node_modules/@pennyfarthing/good/dist/api/good.js',
328
- exportName: 'createGoodRouter',
329
- plugin: '@pennyfarthing/good',
330
- },
331
- ];
332
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
333
- mockGetPluginRouters.mockReturnValue(fakeRouters);
334
- const result = await initPluginRouters(app, '/fake/project');
335
- // Both routers should be attempted
336
- expect(result.routers).toHaveLength(2);
337
- // At least the broken one should fail
338
- const brokenResult = result.routers.find((r) => r.plugin === '@pennyfarthing/broken');
339
- expect(brokenResult?.success).toBe(false);
340
- });
341
- it('should never throw from initPluginRouters', async () => {
342
- // Even if discoverPlugins itself throws, we should catch it
343
- mockDiscoverPlugins.mockImplementation(() => {
344
- throw new Error('Catastrophic failure');
345
- });
346
- const result = await initPluginRouters(app, '/fake/project');
347
- expect(result.discovered).toBe(0);
348
- expect(result.loaded).toBe(0);
349
- expect(result.failed).toBe(0);
350
- });
351
- });
352
- describe('Cyclist starts without plugins', () => {
353
- let app;
354
- beforeEach(() => {
355
- app = express();
356
- vi.clearAllMocks();
357
- });
358
- it('should return clean result when no @pennyfarthing packages exist', async () => {
359
- mockDiscoverPlugins.mockReturnValue([]);
360
- mockGetPluginRouters.mockReturnValue([]);
361
- const result = await initPluginRouters(app, '/fake/project');
362
- expect(result.discovered).toBe(0);
363
- expect(result.loaded).toBe(0);
364
- expect(result.failed).toBe(0);
365
- expect(result.routers).toEqual([]);
366
- });
367
- it('should not modify the Express app when no plugins have routers', async () => {
368
- const fakePlugins = [
369
- {
370
- name: '@pennyfarthing/benchmark',
371
- path: '/node_modules/@pennyfarthing/benchmark',
372
- manifest: { commands: 'commands/', skills: 'skills/' },
373
- // Note: no api field — plugin has commands/skills but no router
374
- },
375
- ];
376
- mockDiscoverPlugins.mockReturnValue(fakePlugins);
377
- mockGetPluginRouters.mockReturnValue([]); // No routers declared
378
- const useSpy = vi.spyOn(app, 'use');
379
- const routesBefore = app._router?.stack?.length ?? 0;
380
- const result = await initPluginRouters(app, '/fake/project');
381
- // Plugin was discovered but has no router
382
- expect(result.discovered).toBe(1);
383
- expect(result.loaded).toBe(0);
384
- // app.use should not have been called for plugin routers
385
- const pluginMountCalls = useSpy.mock.calls.filter((call) => typeof call[0] === 'string' && call[0].startsWith('/api/'));
386
- expect(pluginMountCalls).toHaveLength(0);
387
- });
388
- it('should log discovered plugins for observability', async () => {
389
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
390
- mockDiscoverPlugins.mockReturnValue([
391
- {
392
- name: '@pennyfarthing/benchmark',
393
- path: '/node_modules/@pennyfarthing/benchmark',
394
- manifest: { commands: 'commands/' },
395
- },
396
- ]);
397
- mockGetPluginRouters.mockReturnValue([]);
398
- await initPluginRouters(app, '/fake/project');
399
- // Should log something about plugin discovery
400
- expect(consoleSpy).toHaveBeenCalled();
401
- const logMessages = consoleSpy.mock.calls.map((call) => call.join(' '));
402
- const hasPluginLog = logMessages.some((msg) => msg.includes('plugin') || msg.includes('Plugin'));
403
- expect(hasPluginLog).toBe(true);
404
- consoleSpy.mockRestore();
405
- });
406
- });
407
- //# sourceMappingURL=plugin-loader.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-loader.test.js","sourceRoot":"","sources":["../src/plugin-loader.test.ts"],"names":[],"mappings":"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"}