@renseiai/agentfactory 0.8.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 (246) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -0
  3. package/dist/src/config/index.d.ts +3 -0
  4. package/dist/src/config/index.d.ts.map +1 -0
  5. package/dist/src/config/index.js +1 -0
  6. package/dist/src/config/repository-config.d.ts +44 -0
  7. package/dist/src/config/repository-config.d.ts.map +1 -0
  8. package/dist/src/config/repository-config.js +88 -0
  9. package/dist/src/config/repository-config.test.d.ts +2 -0
  10. package/dist/src/config/repository-config.test.d.ts.map +1 -0
  11. package/dist/src/config/repository-config.test.js +249 -0
  12. package/dist/src/deployment/deployment-checker.d.ts +110 -0
  13. package/dist/src/deployment/deployment-checker.d.ts.map +1 -0
  14. package/dist/src/deployment/deployment-checker.js +242 -0
  15. package/dist/src/deployment/index.d.ts +3 -0
  16. package/dist/src/deployment/index.d.ts.map +1 -0
  17. package/dist/src/deployment/index.js +2 -0
  18. package/dist/src/frontend/index.d.ts +2 -0
  19. package/dist/src/frontend/index.d.ts.map +1 -0
  20. package/dist/src/frontend/index.js +1 -0
  21. package/dist/src/frontend/types.d.ts +106 -0
  22. package/dist/src/frontend/types.d.ts.map +1 -0
  23. package/dist/src/frontend/types.js +11 -0
  24. package/dist/src/governor/decision-engine.d.ts +52 -0
  25. package/dist/src/governor/decision-engine.d.ts.map +1 -0
  26. package/dist/src/governor/decision-engine.js +220 -0
  27. package/dist/src/governor/decision-engine.test.d.ts +2 -0
  28. package/dist/src/governor/decision-engine.test.d.ts.map +1 -0
  29. package/dist/src/governor/decision-engine.test.js +629 -0
  30. package/dist/src/governor/event-bus.d.ts +43 -0
  31. package/dist/src/governor/event-bus.d.ts.map +1 -0
  32. package/dist/src/governor/event-bus.js +8 -0
  33. package/dist/src/governor/event-deduplicator.d.ts +43 -0
  34. package/dist/src/governor/event-deduplicator.d.ts.map +1 -0
  35. package/dist/src/governor/event-deduplicator.js +53 -0
  36. package/dist/src/governor/event-driven-governor.d.ts +131 -0
  37. package/dist/src/governor/event-driven-governor.d.ts.map +1 -0
  38. package/dist/src/governor/event-driven-governor.js +379 -0
  39. package/dist/src/governor/event-driven-governor.test.d.ts +2 -0
  40. package/dist/src/governor/event-driven-governor.test.d.ts.map +1 -0
  41. package/dist/src/governor/event-driven-governor.test.js +673 -0
  42. package/dist/src/governor/event-types.d.ts +78 -0
  43. package/dist/src/governor/event-types.d.ts.map +1 -0
  44. package/dist/src/governor/event-types.js +32 -0
  45. package/dist/src/governor/governor-types.d.ts +82 -0
  46. package/dist/src/governor/governor-types.d.ts.map +1 -0
  47. package/dist/src/governor/governor-types.js +21 -0
  48. package/dist/src/governor/governor.d.ts +100 -0
  49. package/dist/src/governor/governor.d.ts.map +1 -0
  50. package/dist/src/governor/governor.js +262 -0
  51. package/dist/src/governor/governor.test.d.ts +2 -0
  52. package/dist/src/governor/governor.test.d.ts.map +1 -0
  53. package/dist/src/governor/governor.test.js +514 -0
  54. package/dist/src/governor/human-touchpoints.d.ts +131 -0
  55. package/dist/src/governor/human-touchpoints.d.ts.map +1 -0
  56. package/dist/src/governor/human-touchpoints.js +251 -0
  57. package/dist/src/governor/human-touchpoints.test.d.ts +2 -0
  58. package/dist/src/governor/human-touchpoints.test.d.ts.map +1 -0
  59. package/dist/src/governor/human-touchpoints.test.js +366 -0
  60. package/dist/src/governor/in-memory-event-bus.d.ts +29 -0
  61. package/dist/src/governor/in-memory-event-bus.d.ts.map +1 -0
  62. package/dist/src/governor/in-memory-event-bus.js +79 -0
  63. package/dist/src/governor/index.d.ts +14 -0
  64. package/dist/src/governor/index.d.ts.map +1 -0
  65. package/dist/src/governor/index.js +13 -0
  66. package/dist/src/governor/override-parser.d.ts +60 -0
  67. package/dist/src/governor/override-parser.d.ts.map +1 -0
  68. package/dist/src/governor/override-parser.js +98 -0
  69. package/dist/src/governor/override-parser.test.d.ts +2 -0
  70. package/dist/src/governor/override-parser.test.d.ts.map +1 -0
  71. package/dist/src/governor/override-parser.test.js +312 -0
  72. package/dist/src/governor/platform-adapter.d.ts +69 -0
  73. package/dist/src/governor/platform-adapter.d.ts.map +1 -0
  74. package/dist/src/governor/platform-adapter.js +11 -0
  75. package/dist/src/governor/processing-state.d.ts +66 -0
  76. package/dist/src/governor/processing-state.d.ts.map +1 -0
  77. package/dist/src/governor/processing-state.js +43 -0
  78. package/dist/src/governor/processing-state.test.d.ts +2 -0
  79. package/dist/src/governor/processing-state.test.d.ts.map +1 -0
  80. package/dist/src/governor/processing-state.test.js +96 -0
  81. package/dist/src/governor/top-of-funnel.d.ts +118 -0
  82. package/dist/src/governor/top-of-funnel.d.ts.map +1 -0
  83. package/dist/src/governor/top-of-funnel.js +168 -0
  84. package/dist/src/governor/top-of-funnel.test.d.ts +2 -0
  85. package/dist/src/governor/top-of-funnel.test.d.ts.map +1 -0
  86. package/dist/src/governor/top-of-funnel.test.js +331 -0
  87. package/dist/src/index.d.ts +11 -0
  88. package/dist/src/index.d.ts.map +1 -0
  89. package/dist/src/index.js +10 -0
  90. package/dist/src/linear-cli.d.ts +38 -0
  91. package/dist/src/linear-cli.d.ts.map +1 -0
  92. package/dist/src/linear-cli.js +674 -0
  93. package/dist/src/logger.d.ts +117 -0
  94. package/dist/src/logger.d.ts.map +1 -0
  95. package/dist/src/logger.js +430 -0
  96. package/dist/src/manifest/generate.d.ts +20 -0
  97. package/dist/src/manifest/generate.d.ts.map +1 -0
  98. package/dist/src/manifest/generate.js +65 -0
  99. package/dist/src/manifest/index.d.ts +4 -0
  100. package/dist/src/manifest/index.d.ts.map +1 -0
  101. package/dist/src/manifest/index.js +2 -0
  102. package/dist/src/manifest/route-manifest.d.ts +34 -0
  103. package/dist/src/manifest/route-manifest.d.ts.map +1 -0
  104. package/dist/src/manifest/route-manifest.js +148 -0
  105. package/dist/src/orchestrator/activity-emitter.d.ts +119 -0
  106. package/dist/src/orchestrator/activity-emitter.d.ts.map +1 -0
  107. package/dist/src/orchestrator/activity-emitter.js +306 -0
  108. package/dist/src/orchestrator/api-activity-emitter.d.ts +167 -0
  109. package/dist/src/orchestrator/api-activity-emitter.d.ts.map +1 -0
  110. package/dist/src/orchestrator/api-activity-emitter.js +417 -0
  111. package/dist/src/orchestrator/heartbeat-writer.d.ts +57 -0
  112. package/dist/src/orchestrator/heartbeat-writer.d.ts.map +1 -0
  113. package/dist/src/orchestrator/heartbeat-writer.js +137 -0
  114. package/dist/src/orchestrator/index.d.ts +20 -0
  115. package/dist/src/orchestrator/index.d.ts.map +1 -0
  116. package/dist/src/orchestrator/index.js +22 -0
  117. package/dist/src/orchestrator/log-analyzer.d.ts +160 -0
  118. package/dist/src/orchestrator/log-analyzer.d.ts.map +1 -0
  119. package/dist/src/orchestrator/log-analyzer.js +572 -0
  120. package/dist/src/orchestrator/log-config.d.ts +39 -0
  121. package/dist/src/orchestrator/log-config.d.ts.map +1 -0
  122. package/dist/src/orchestrator/log-config.js +45 -0
  123. package/dist/src/orchestrator/orchestrator.d.ts +316 -0
  124. package/dist/src/orchestrator/orchestrator.d.ts.map +1 -0
  125. package/dist/src/orchestrator/orchestrator.js +3290 -0
  126. package/dist/src/orchestrator/parse-work-result.d.ts +16 -0
  127. package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -0
  128. package/dist/src/orchestrator/parse-work-result.js +135 -0
  129. package/dist/src/orchestrator/parse-work-result.test.d.ts +2 -0
  130. package/dist/src/orchestrator/parse-work-result.test.d.ts.map +1 -0
  131. package/dist/src/orchestrator/parse-work-result.test.js +234 -0
  132. package/dist/src/orchestrator/progress-logger.d.ts +72 -0
  133. package/dist/src/orchestrator/progress-logger.d.ts.map +1 -0
  134. package/dist/src/orchestrator/progress-logger.js +135 -0
  135. package/dist/src/orchestrator/session-logger.d.ts +159 -0
  136. package/dist/src/orchestrator/session-logger.d.ts.map +1 -0
  137. package/dist/src/orchestrator/session-logger.js +275 -0
  138. package/dist/src/orchestrator/state-recovery.d.ts +96 -0
  139. package/dist/src/orchestrator/state-recovery.d.ts.map +1 -0
  140. package/dist/src/orchestrator/state-recovery.js +302 -0
  141. package/dist/src/orchestrator/state-types.d.ts +165 -0
  142. package/dist/src/orchestrator/state-types.d.ts.map +1 -0
  143. package/dist/src/orchestrator/state-types.js +7 -0
  144. package/dist/src/orchestrator/stream-parser.d.ts +151 -0
  145. package/dist/src/orchestrator/stream-parser.d.ts.map +1 -0
  146. package/dist/src/orchestrator/stream-parser.js +137 -0
  147. package/dist/src/orchestrator/types.d.ts +232 -0
  148. package/dist/src/orchestrator/types.d.ts.map +1 -0
  149. package/dist/src/orchestrator/types.js +4 -0
  150. package/dist/src/orchestrator/validate-git-remote.test.d.ts +2 -0
  151. package/dist/src/orchestrator/validate-git-remote.test.d.ts.map +1 -0
  152. package/dist/src/orchestrator/validate-git-remote.test.js +61 -0
  153. package/dist/src/providers/a2a-auth.d.ts +81 -0
  154. package/dist/src/providers/a2a-auth.d.ts.map +1 -0
  155. package/dist/src/providers/a2a-auth.js +188 -0
  156. package/dist/src/providers/a2a-auth.test.d.ts +2 -0
  157. package/dist/src/providers/a2a-auth.test.d.ts.map +1 -0
  158. package/dist/src/providers/a2a-auth.test.js +232 -0
  159. package/dist/src/providers/a2a-provider.d.ts +254 -0
  160. package/dist/src/providers/a2a-provider.d.ts.map +1 -0
  161. package/dist/src/providers/a2a-provider.integration.test.d.ts +9 -0
  162. package/dist/src/providers/a2a-provider.integration.test.d.ts.map +1 -0
  163. package/dist/src/providers/a2a-provider.integration.test.js +665 -0
  164. package/dist/src/providers/a2a-provider.js +811 -0
  165. package/dist/src/providers/a2a-provider.test.d.ts +2 -0
  166. package/dist/src/providers/a2a-provider.test.d.ts.map +1 -0
  167. package/dist/src/providers/a2a-provider.test.js +681 -0
  168. package/dist/src/providers/amp-provider.d.ts +20 -0
  169. package/dist/src/providers/amp-provider.d.ts.map +1 -0
  170. package/dist/src/providers/amp-provider.js +24 -0
  171. package/dist/src/providers/claude-provider.d.ts +18 -0
  172. package/dist/src/providers/claude-provider.d.ts.map +1 -0
  173. package/dist/src/providers/claude-provider.js +437 -0
  174. package/dist/src/providers/codex-provider.d.ts +133 -0
  175. package/dist/src/providers/codex-provider.d.ts.map +1 -0
  176. package/dist/src/providers/codex-provider.js +381 -0
  177. package/dist/src/providers/codex-provider.test.d.ts +2 -0
  178. package/dist/src/providers/codex-provider.test.d.ts.map +1 -0
  179. package/dist/src/providers/codex-provider.test.js +387 -0
  180. package/dist/src/providers/index.d.ts +44 -0
  181. package/dist/src/providers/index.d.ts.map +1 -0
  182. package/dist/src/providers/index.js +85 -0
  183. package/dist/src/providers/spring-ai-provider.d.ts +90 -0
  184. package/dist/src/providers/spring-ai-provider.d.ts.map +1 -0
  185. package/dist/src/providers/spring-ai-provider.integration.test.d.ts +13 -0
  186. package/dist/src/providers/spring-ai-provider.integration.test.d.ts.map +1 -0
  187. package/dist/src/providers/spring-ai-provider.integration.test.js +351 -0
  188. package/dist/src/providers/spring-ai-provider.js +317 -0
  189. package/dist/src/providers/spring-ai-provider.test.d.ts +2 -0
  190. package/dist/src/providers/spring-ai-provider.test.d.ts.map +1 -0
  191. package/dist/src/providers/spring-ai-provider.test.js +200 -0
  192. package/dist/src/providers/types.d.ts +165 -0
  193. package/dist/src/providers/types.d.ts.map +1 -0
  194. package/dist/src/providers/types.js +13 -0
  195. package/dist/src/templates/adapters.d.ts +51 -0
  196. package/dist/src/templates/adapters.d.ts.map +1 -0
  197. package/dist/src/templates/adapters.js +104 -0
  198. package/dist/src/templates/adapters.test.d.ts +2 -0
  199. package/dist/src/templates/adapters.test.d.ts.map +1 -0
  200. package/dist/src/templates/adapters.test.js +165 -0
  201. package/dist/src/templates/agent-definition.d.ts +85 -0
  202. package/dist/src/templates/agent-definition.d.ts.map +1 -0
  203. package/dist/src/templates/agent-definition.js +97 -0
  204. package/dist/src/templates/agent-definition.test.d.ts +2 -0
  205. package/dist/src/templates/agent-definition.test.d.ts.map +1 -0
  206. package/dist/src/templates/agent-definition.test.js +209 -0
  207. package/dist/src/templates/index.d.ts +14 -0
  208. package/dist/src/templates/index.d.ts.map +1 -0
  209. package/dist/src/templates/index.js +11 -0
  210. package/dist/src/templates/loader.d.ts +41 -0
  211. package/dist/src/templates/loader.d.ts.map +1 -0
  212. package/dist/src/templates/loader.js +114 -0
  213. package/dist/src/templates/registry.d.ts +80 -0
  214. package/dist/src/templates/registry.d.ts.map +1 -0
  215. package/dist/src/templates/registry.js +177 -0
  216. package/dist/src/templates/registry.test.d.ts +2 -0
  217. package/dist/src/templates/registry.test.d.ts.map +1 -0
  218. package/dist/src/templates/registry.test.js +198 -0
  219. package/dist/src/templates/renderer.d.ts +29 -0
  220. package/dist/src/templates/renderer.d.ts.map +1 -0
  221. package/dist/src/templates/renderer.js +35 -0
  222. package/dist/src/templates/strategy-templates.test.d.ts +2 -0
  223. package/dist/src/templates/strategy-templates.test.d.ts.map +1 -0
  224. package/dist/src/templates/strategy-templates.test.js +619 -0
  225. package/dist/src/templates/types.d.ts +233 -0
  226. package/dist/src/templates/types.d.ts.map +1 -0
  227. package/dist/src/templates/types.js +127 -0
  228. package/dist/src/templates/types.test.d.ts +2 -0
  229. package/dist/src/templates/types.test.d.ts.map +1 -0
  230. package/dist/src/templates/types.test.js +232 -0
  231. package/dist/src/tools/index.d.ts +6 -0
  232. package/dist/src/tools/index.d.ts.map +1 -0
  233. package/dist/src/tools/index.js +3 -0
  234. package/dist/src/tools/linear-runner.d.ts +34 -0
  235. package/dist/src/tools/linear-runner.d.ts.map +1 -0
  236. package/dist/src/tools/linear-runner.js +700 -0
  237. package/dist/src/tools/plugins/linear.d.ts +9 -0
  238. package/dist/src/tools/plugins/linear.d.ts.map +1 -0
  239. package/dist/src/tools/plugins/linear.js +138 -0
  240. package/dist/src/tools/registry.d.ts +9 -0
  241. package/dist/src/tools/registry.d.ts.map +1 -0
  242. package/dist/src/tools/registry.js +18 -0
  243. package/dist/src/tools/types.d.ts +18 -0
  244. package/dist/src/tools/types.d.ts.map +1 -0
  245. package/dist/src/tools/types.js +1 -0
  246. package/package.json +78 -0
@@ -0,0 +1,387 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mapCodexEvent, mapCodexItemEvent, } from './codex-provider.js';
3
+ function freshState() {
4
+ return {
5
+ sessionId: null,
6
+ totalInputTokens: 0,
7
+ totalOutputTokens: 0,
8
+ turnCount: 0,
9
+ };
10
+ }
11
+ describe('mapCodexEvent', () => {
12
+ it('maps thread.started to init', () => {
13
+ const state = freshState();
14
+ const event = { type: 'thread.started', thread_id: 'thread-abc' };
15
+ const result = mapCodexEvent(event, state);
16
+ expect(result).toHaveLength(1);
17
+ expect(result[0]).toMatchObject({
18
+ type: 'init',
19
+ sessionId: 'thread-abc',
20
+ });
21
+ expect(state.sessionId).toBe('thread-abc');
22
+ });
23
+ it('maps turn.started to system with incrementing turn count', () => {
24
+ const state = freshState();
25
+ const event = { type: 'turn.started' };
26
+ const r1 = mapCodexEvent(event, state);
27
+ expect(r1[0]).toMatchObject({
28
+ type: 'system',
29
+ subtype: 'turn_started',
30
+ message: 'Turn 1 started',
31
+ });
32
+ expect(state.turnCount).toBe(1);
33
+ const r2 = mapCodexEvent(event, state);
34
+ expect(r2[0]).toMatchObject({ message: 'Turn 2 started' });
35
+ expect(state.turnCount).toBe(2);
36
+ });
37
+ it('maps turn.completed to result with accumulated usage', () => {
38
+ const state = freshState();
39
+ state.turnCount = 1;
40
+ const event = {
41
+ type: 'turn.completed',
42
+ usage: { input_tokens: 100, output_tokens: 50, cached_input_tokens: 20 },
43
+ };
44
+ const result = mapCodexEvent(event, state);
45
+ expect(result).toHaveLength(1);
46
+ expect(result[0]).toMatchObject({
47
+ type: 'result',
48
+ success: true,
49
+ cost: {
50
+ inputTokens: 100,
51
+ outputTokens: 50,
52
+ numTurns: 1,
53
+ },
54
+ });
55
+ expect(state.totalInputTokens).toBe(100);
56
+ expect(state.totalOutputTokens).toBe(50);
57
+ });
58
+ it('accumulates usage across multiple turns', () => {
59
+ const state = freshState();
60
+ state.turnCount = 2;
61
+ mapCodexEvent({ type: 'turn.completed', usage: { input_tokens: 100, output_tokens: 50 } }, state);
62
+ const result = mapCodexEvent({ type: 'turn.completed', usage: { input_tokens: 200, output_tokens: 80 } }, state);
63
+ expect(result[0]).toMatchObject({
64
+ type: 'result',
65
+ success: true,
66
+ cost: { inputTokens: 300, outputTokens: 130 },
67
+ });
68
+ });
69
+ it('maps turn.completed without usage', () => {
70
+ const state = freshState();
71
+ const result = mapCodexEvent({ type: 'turn.completed' }, state);
72
+ expect(result[0]).toMatchObject({ type: 'result', success: true });
73
+ });
74
+ it('maps turn.failed to failed result', () => {
75
+ const state = freshState();
76
+ const event = {
77
+ type: 'turn.failed',
78
+ error: { message: 'Model error' },
79
+ };
80
+ const result = mapCodexEvent(event, state);
81
+ expect(result[0]).toMatchObject({
82
+ type: 'result',
83
+ success: false,
84
+ errors: ['Model error'],
85
+ errorSubtype: 'turn_failed',
86
+ });
87
+ });
88
+ it('maps turn.failed without error message', () => {
89
+ const state = freshState();
90
+ const result = mapCodexEvent({ type: 'turn.failed' }, state);
91
+ expect(result[0]).toMatchObject({
92
+ type: 'result',
93
+ success: false,
94
+ errors: ['Turn failed'],
95
+ });
96
+ });
97
+ it('maps error event', () => {
98
+ const state = freshState();
99
+ const event = { type: 'error', message: 'Connection lost' };
100
+ const result = mapCodexEvent(event, state);
101
+ expect(result[0]).toMatchObject({
102
+ type: 'error',
103
+ message: 'Connection lost',
104
+ });
105
+ });
106
+ it('maps error event without message', () => {
107
+ const state = freshState();
108
+ const result = mapCodexEvent({ type: 'error' }, state);
109
+ expect(result[0]).toMatchObject({
110
+ type: 'error',
111
+ message: 'Unknown error',
112
+ });
113
+ });
114
+ it('delegates item events to mapCodexItemEvent', () => {
115
+ const state = freshState();
116
+ const event = {
117
+ type: 'item.completed',
118
+ item: { id: 'msg-1', type: 'agent_message', text: 'Hello' },
119
+ };
120
+ const result = mapCodexEvent(event, state);
121
+ expect(result[0]).toMatchObject({
122
+ type: 'assistant_text',
123
+ text: 'Hello',
124
+ });
125
+ });
126
+ it('handles unknown event type gracefully', () => {
127
+ const state = freshState();
128
+ const event = { type: 'unknown.event' };
129
+ const result = mapCodexEvent(event, state);
130
+ expect(result[0]).toMatchObject({
131
+ type: 'system',
132
+ subtype: 'unknown',
133
+ });
134
+ });
135
+ });
136
+ describe('mapCodexItemEvent', () => {
137
+ it('maps agent_message to assistant_text', () => {
138
+ const event = {
139
+ type: 'item.completed',
140
+ item: { id: 'msg-1', type: 'agent_message', text: 'Analysis complete' },
141
+ };
142
+ const result = mapCodexItemEvent(event);
143
+ expect(result).toEqual([{
144
+ type: 'assistant_text',
145
+ text: 'Analysis complete',
146
+ raw: event,
147
+ }]);
148
+ });
149
+ it('maps reasoning to system event', () => {
150
+ const event = {
151
+ type: 'item.completed',
152
+ item: { id: 'r-1', type: 'reasoning', text: 'Thinking about the problem...' },
153
+ };
154
+ const result = mapCodexItemEvent(event);
155
+ expect(result[0]).toMatchObject({
156
+ type: 'system',
157
+ subtype: 'reasoning',
158
+ message: 'Thinking about the problem...',
159
+ });
160
+ });
161
+ it('maps command_execution item.started to tool_use', () => {
162
+ const event = {
163
+ type: 'item.started',
164
+ item: {
165
+ id: 'cmd-1',
166
+ type: 'command_execution',
167
+ command: 'ls -la',
168
+ aggregated_output: '',
169
+ status: 'in_progress',
170
+ },
171
+ };
172
+ const result = mapCodexItemEvent(event);
173
+ expect(result[0]).toMatchObject({
174
+ type: 'tool_use',
175
+ toolName: 'shell',
176
+ toolUseId: 'cmd-1',
177
+ input: { command: 'ls -la' },
178
+ });
179
+ });
180
+ it('maps command_execution item.completed to tool_result', () => {
181
+ const event = {
182
+ type: 'item.completed',
183
+ item: {
184
+ id: 'cmd-1',
185
+ type: 'command_execution',
186
+ command: 'ls -la',
187
+ aggregated_output: 'file1.txt\nfile2.txt',
188
+ exit_code: 0,
189
+ status: 'completed',
190
+ },
191
+ };
192
+ const result = mapCodexItemEvent(event);
193
+ expect(result[0]).toMatchObject({
194
+ type: 'tool_result',
195
+ toolName: 'shell',
196
+ toolUseId: 'cmd-1',
197
+ content: 'file1.txt\nfile2.txt',
198
+ isError: false,
199
+ });
200
+ });
201
+ it('marks command_execution as error on non-zero exit code', () => {
202
+ const event = {
203
+ type: 'item.completed',
204
+ item: {
205
+ id: 'cmd-1',
206
+ type: 'command_execution',
207
+ command: 'false',
208
+ aggregated_output: '',
209
+ exit_code: 1,
210
+ status: 'failed',
211
+ },
212
+ };
213
+ const result = mapCodexItemEvent(event);
214
+ expect(result[0]).toMatchObject({
215
+ type: 'tool_result',
216
+ isError: true,
217
+ });
218
+ });
219
+ it('maps command_execution item.updated to progress', () => {
220
+ const event = {
221
+ type: 'item.updated',
222
+ item: {
223
+ id: 'cmd-1',
224
+ type: 'command_execution',
225
+ command: 'npm install',
226
+ aggregated_output: 'Installing...',
227
+ status: 'in_progress',
228
+ },
229
+ };
230
+ const result = mapCodexItemEvent(event);
231
+ expect(result[0]).toMatchObject({
232
+ type: 'system',
233
+ subtype: 'command_progress',
234
+ message: 'Command: npm install (in_progress)',
235
+ });
236
+ });
237
+ it('maps file_change to tool_result', () => {
238
+ const event = {
239
+ type: 'item.completed',
240
+ item: {
241
+ id: 'fc-1',
242
+ type: 'file_change',
243
+ changes: [
244
+ { path: 'src/index.ts', kind: 'update' },
245
+ { path: 'src/new.ts', kind: 'add' },
246
+ ],
247
+ status: 'completed',
248
+ },
249
+ };
250
+ const result = mapCodexItemEvent(event);
251
+ expect(result[0]).toMatchObject({
252
+ type: 'tool_result',
253
+ toolName: 'file_change',
254
+ content: 'update: src/index.ts\nadd: src/new.ts',
255
+ isError: false,
256
+ });
257
+ });
258
+ it('maps mcp_tool_call item.started to tool_use', () => {
259
+ const event = {
260
+ type: 'item.started',
261
+ item: {
262
+ id: 'mcp-1',
263
+ type: 'mcp_tool_call',
264
+ server: 'linear',
265
+ tool: 'create_issue',
266
+ arguments: { title: 'Test' },
267
+ status: 'in_progress',
268
+ },
269
+ };
270
+ const result = mapCodexItemEvent(event);
271
+ expect(result[0]).toMatchObject({
272
+ type: 'tool_use',
273
+ toolName: 'mcp:linear/create_issue',
274
+ toolUseId: 'mcp-1',
275
+ input: { title: 'Test' },
276
+ });
277
+ });
278
+ it('maps mcp_tool_call item.completed to tool_result', () => {
279
+ const event = {
280
+ type: 'item.completed',
281
+ item: {
282
+ id: 'mcp-1',
283
+ type: 'mcp_tool_call',
284
+ server: 'linear',
285
+ tool: 'create_issue',
286
+ arguments: { title: 'Test' },
287
+ result: { content: [{ text: 'Created' }] },
288
+ status: 'completed',
289
+ },
290
+ };
291
+ const result = mapCodexItemEvent(event);
292
+ expect(result[0]).toMatchObject({
293
+ type: 'tool_result',
294
+ toolName: 'mcp:linear/create_issue',
295
+ content: '[{"text":"Created"}]',
296
+ isError: false,
297
+ });
298
+ });
299
+ it('maps mcp_tool_call error', () => {
300
+ const event = {
301
+ type: 'item.completed',
302
+ item: {
303
+ id: 'mcp-1',
304
+ type: 'mcp_tool_call',
305
+ server: 'linear',
306
+ tool: 'create_issue',
307
+ arguments: {},
308
+ error: { message: 'Auth failed' },
309
+ status: 'failed',
310
+ },
311
+ };
312
+ const result = mapCodexItemEvent(event);
313
+ expect(result[0]).toMatchObject({
314
+ type: 'tool_result',
315
+ isError: true,
316
+ content: 'Auth failed',
317
+ });
318
+ });
319
+ it('returns empty array for mcp_tool_call item.updated', () => {
320
+ const event = {
321
+ type: 'item.updated',
322
+ item: {
323
+ id: 'mcp-1',
324
+ type: 'mcp_tool_call',
325
+ server: 'linear',
326
+ tool: 'create_issue',
327
+ arguments: {},
328
+ status: 'in_progress',
329
+ },
330
+ };
331
+ const result = mapCodexItemEvent(event);
332
+ expect(result).toEqual([]);
333
+ });
334
+ it('maps todo_list to system event', () => {
335
+ const event = {
336
+ type: 'item.completed',
337
+ item: {
338
+ id: 'todo-1',
339
+ type: 'todo_list',
340
+ items: [
341
+ { text: 'Read files', completed: true },
342
+ { text: 'Write tests', completed: false },
343
+ ],
344
+ },
345
+ };
346
+ const result = mapCodexItemEvent(event);
347
+ expect(result[0]).toMatchObject({
348
+ type: 'system',
349
+ subtype: 'todo_list',
350
+ message: '[x] Read files\n[ ] Write tests',
351
+ });
352
+ });
353
+ it('maps error item to error event', () => {
354
+ const event = {
355
+ type: 'item.completed',
356
+ item: { id: 'err-1', type: 'error', message: 'Something went wrong' },
357
+ };
358
+ const result = mapCodexItemEvent(event);
359
+ expect(result[0]).toMatchObject({
360
+ type: 'error',
361
+ message: 'Something went wrong',
362
+ });
363
+ });
364
+ it('handles unknown item type', () => {
365
+ const event = {
366
+ type: 'item.completed',
367
+ item: { id: 'x', type: 'web_search' },
368
+ };
369
+ const result = mapCodexItemEvent(event);
370
+ expect(result[0]).toMatchObject({
371
+ type: 'system',
372
+ subtype: 'unknown_item',
373
+ });
374
+ });
375
+ });
376
+ describe('CodexProvider', () => {
377
+ it('exports CodexProvider class', async () => {
378
+ const { CodexProvider } = await import('./codex-provider.js');
379
+ const provider = new CodexProvider();
380
+ expect(provider.name).toBe('codex');
381
+ });
382
+ it('exports createCodexProvider factory', async () => {
383
+ const { createCodexProvider } = await import('./codex-provider.js');
384
+ const provider = createCodexProvider();
385
+ expect(provider.name).toBe('codex');
386
+ });
387
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Agent Provider Factory
3
+ *
4
+ * Creates provider instances based on name.
5
+ * Supports provider selection via env vars:
6
+ * AGENT_PROVIDER=claude (global default)
7
+ * AGENT_PROVIDER_SOCIAL=codex (per-project override)
8
+ * AGENT_PROVIDER_QA=amp (per-work-type override)
9
+ *
10
+ * Resolution order: work-type → project → env default → 'claude'
11
+ */
12
+ export type { AgentProviderName, AgentProvider, AgentSpawnConfig, AgentHandle, AgentEvent } from './types.js';
13
+ export type { AgentInitEvent, AgentSystemEvent, AgentAssistantTextEvent, AgentToolUseEvent, AgentToolResultEvent, AgentToolProgressEvent, AgentResultEvent, AgentErrorEvent, AgentCostData, } from './types.js';
14
+ export { ClaudeProvider, createClaudeProvider } from './claude-provider.js';
15
+ export { CodexProvider, createCodexProvider } from './codex-provider.js';
16
+ export { AmpProvider, createAmpProvider } from './amp-provider.js';
17
+ export { SpringAiProvider, createSpringAiProvider } from './spring-ai-provider.js';
18
+ export { A2aProvider, createA2aProvider } from './a2a-provider.js';
19
+ import type { AgentProvider, AgentProviderName } from './types.js';
20
+ /**
21
+ * Create a provider instance by name.
22
+ *
23
+ * @param name - Provider name ('claude', 'codex', 'amp', 'spring-ai', 'a2a')
24
+ * @returns AgentProvider instance
25
+ * @throws Error if provider name is unknown
26
+ */
27
+ export declare function createProvider(name: AgentProviderName): AgentProvider;
28
+ /**
29
+ * Resolve which provider to use based on env vars, project, and work type.
30
+ *
31
+ * Resolution order (highest priority first):
32
+ * 1. AGENT_PROVIDER_{WORKTYPE} (e.g., AGENT_PROVIDER_QA=amp)
33
+ * 2. AGENT_PROVIDER_{PROJECT} (e.g., AGENT_PROVIDER_SOCIAL=codex)
34
+ * 3. AGENT_PROVIDER (global default)
35
+ * 4. 'claude' (fallback)
36
+ *
37
+ * @param options - Project and work type context for resolution
38
+ * @returns The resolved provider name
39
+ */
40
+ export declare function resolveProviderName(options?: {
41
+ project?: string;
42
+ workType?: string;
43
+ }): AgentProviderName;
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC7G,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAClF,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAOlE;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAerE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GAAG,iBAAiB,CA2BpB"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Agent Provider Factory
3
+ *
4
+ * Creates provider instances based on name.
5
+ * Supports provider selection via env vars:
6
+ * AGENT_PROVIDER=claude (global default)
7
+ * AGENT_PROVIDER_SOCIAL=codex (per-project override)
8
+ * AGENT_PROVIDER_QA=amp (per-work-type override)
9
+ *
10
+ * Resolution order: work-type → project → env default → 'claude'
11
+ */
12
+ export { ClaudeProvider, createClaudeProvider } from './claude-provider.js';
13
+ export { CodexProvider, createCodexProvider } from './codex-provider.js';
14
+ export { AmpProvider, createAmpProvider } from './amp-provider.js';
15
+ export { SpringAiProvider, createSpringAiProvider } from './spring-ai-provider.js';
16
+ export { A2aProvider, createA2aProvider } from './a2a-provider.js';
17
+ import { ClaudeProvider } from './claude-provider.js';
18
+ import { CodexProvider } from './codex-provider.js';
19
+ import { AmpProvider } from './amp-provider.js';
20
+ import { SpringAiProvider } from './spring-ai-provider.js';
21
+ import { A2aProvider } from './a2a-provider.js';
22
+ /**
23
+ * Create a provider instance by name.
24
+ *
25
+ * @param name - Provider name ('claude', 'codex', 'amp', 'spring-ai', 'a2a')
26
+ * @returns AgentProvider instance
27
+ * @throws Error if provider name is unknown
28
+ */
29
+ export function createProvider(name) {
30
+ switch (name) {
31
+ case 'claude':
32
+ return new ClaudeProvider();
33
+ case 'codex':
34
+ return new CodexProvider();
35
+ case 'amp':
36
+ return new AmpProvider();
37
+ case 'spring-ai':
38
+ return new SpringAiProvider();
39
+ case 'a2a':
40
+ return new A2aProvider();
41
+ default:
42
+ throw new Error(`Unknown agent provider: ${name}. Supported: claude, codex, amp, spring-ai, a2a`);
43
+ }
44
+ }
45
+ /**
46
+ * Resolve which provider to use based on env vars, project, and work type.
47
+ *
48
+ * Resolution order (highest priority first):
49
+ * 1. AGENT_PROVIDER_{WORKTYPE} (e.g., AGENT_PROVIDER_QA=amp)
50
+ * 2. AGENT_PROVIDER_{PROJECT} (e.g., AGENT_PROVIDER_SOCIAL=codex)
51
+ * 3. AGENT_PROVIDER (global default)
52
+ * 4. 'claude' (fallback)
53
+ *
54
+ * @param options - Project and work type context for resolution
55
+ * @returns The resolved provider name
56
+ */
57
+ export function resolveProviderName(options) {
58
+ // Check work-type-specific override
59
+ if (options?.workType) {
60
+ const workTypeKey = `AGENT_PROVIDER_${options.workType.toUpperCase().replace(/-/g, '_')}`;
61
+ const workTypeProvider = process.env[workTypeKey];
62
+ if (workTypeProvider && isValidProviderName(workTypeProvider)) {
63
+ return workTypeProvider;
64
+ }
65
+ }
66
+ // Check project-specific override
67
+ if (options?.project) {
68
+ const projectKey = `AGENT_PROVIDER_${options.project.toUpperCase()}`;
69
+ const projectProvider = process.env[projectKey];
70
+ if (projectProvider && isValidProviderName(projectProvider)) {
71
+ return projectProvider;
72
+ }
73
+ }
74
+ // Check global default
75
+ const globalProvider = process.env.AGENT_PROVIDER;
76
+ if (globalProvider && isValidProviderName(globalProvider)) {
77
+ return globalProvider;
78
+ }
79
+ // Fallback
80
+ return 'claude';
81
+ }
82
+ const VALID_PROVIDER_NAMES = ['claude', 'codex', 'amp', 'spring-ai', 'a2a'];
83
+ function isValidProviderName(name) {
84
+ return VALID_PROVIDER_NAMES.includes(name);
85
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Spring AI Agent Provider
3
+ *
4
+ * Spawns a Spring AI agent JAR as a child process and parses its JSONL event
5
+ * stream into normalized AgentEvents.
6
+ *
7
+ * CLI invocation patterns:
8
+ * New session: java -jar <JAR> --prompt "<prompt>" --cwd <cwd> --json
9
+ * Resume: java -jar <JAR> --resume <sessionId> --prompt "<prompt>" --cwd <cwd> --json
10
+ *
11
+ * JSONL event types:
12
+ * session.started → init (sessionId)
13
+ * turn.started → system (turn_started)
14
+ * turn.completed → result (success, usage)
15
+ * turn.failed → result (failure)
16
+ * tool.invocation → tool_use
17
+ * tool.result → tool_result
18
+ * assistant.message → assistant_text
19
+ * error → error
20
+ */
21
+ import type { AgentProvider, AgentSpawnConfig, AgentHandle, AgentEvent } from './types.js';
22
+ interface SpringAiSessionStarted {
23
+ type: 'session.started';
24
+ session_id: string;
25
+ }
26
+ interface SpringAiTurnStarted {
27
+ type: 'turn.started';
28
+ }
29
+ interface SpringAiTurnCompleted {
30
+ type: 'turn.completed';
31
+ usage?: {
32
+ input_tokens?: number;
33
+ output_tokens?: number;
34
+ model?: string;
35
+ };
36
+ }
37
+ interface SpringAiTurnFailed {
38
+ type: 'turn.failed';
39
+ error?: {
40
+ message?: string;
41
+ code?: string;
42
+ };
43
+ }
44
+ interface SpringAiAssistantMessage {
45
+ type: 'assistant.message';
46
+ id?: string;
47
+ text: string;
48
+ }
49
+ interface SpringAiToolInvocation {
50
+ type: 'tool.invocation';
51
+ id: string;
52
+ tool_name: string;
53
+ input: Record<string, unknown>;
54
+ }
55
+ interface SpringAiToolResult {
56
+ type: 'tool.result';
57
+ id: string;
58
+ tool_name?: string;
59
+ content: string;
60
+ is_error: boolean;
61
+ }
62
+ interface SpringAiErrorEvent {
63
+ type: 'error';
64
+ message?: string;
65
+ code?: string;
66
+ }
67
+ export type SpringAiEvent = SpringAiSessionStarted | SpringAiTurnStarted | SpringAiTurnCompleted | SpringAiTurnFailed | SpringAiAssistantMessage | SpringAiToolInvocation | SpringAiToolResult | SpringAiErrorEvent;
68
+ export interface SpringAiEventMapperState {
69
+ sessionId: string | null;
70
+ totalInputTokens: number;
71
+ totalOutputTokens: number;
72
+ turnCount: number;
73
+ }
74
+ /**
75
+ * Map a single Spring AI JSONL event to one or more normalized AgentEvents.
76
+ * Exported for unit testing — the AgentHandle uses this internally.
77
+ */
78
+ export declare function mapSpringAiEvent(event: SpringAiEvent, state: SpringAiEventMapperState): AgentEvent[];
79
+ export declare class SpringAiProvider implements AgentProvider {
80
+ readonly name: "spring-ai";
81
+ spawn(config: AgentSpawnConfig): AgentHandle;
82
+ resume(sessionId: string, config: AgentSpawnConfig): AgentHandle;
83
+ private createHandle;
84
+ }
85
+ /**
86
+ * Create a new Spring AI provider instance
87
+ */
88
+ export declare function createSpringAiProvider(): SpringAiProvider;
89
+ export {};
90
+ //# sourceMappingURL=spring-ai-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring-ai-provider.d.ts","sourceRoot":"","sources":["../../../src/providers/spring-ai-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,UAAU,EACX,MAAM,YAAY,CAAA;AAMnB,UAAU,sBAAsB;IAC9B,IAAI,EAAE,iBAAiB,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,UAAU,mBAAmB;IAC3B,IAAI,EAAE,cAAc,CAAA;CACrB;AAED,UAAU,qBAAqB;IAC7B,IAAI,EAAE,gBAAgB,CAAA;IACtB,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAED,UAAU,kBAAkB;IAC1B,IAAI,EAAE,aAAa,CAAA;IACnB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC5C;AAED,UAAU,wBAAwB;IAChC,IAAI,EAAE,mBAAmB,CAAA;IACzB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;CACb;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,iBAAiB,CAAA;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED,UAAU,kBAAkB;IAC1B,IAAI,EAAE,aAAa,CAAA;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,UAAU,kBAAkB;IAC1B,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,aAAa,GACrB,sBAAsB,GACtB,mBAAmB,GACnB,qBAAqB,GACrB,kBAAkB,GAClB,wBAAwB,GACxB,sBAAsB,GACtB,kBAAkB,GAClB,kBAAkB,CAAA;AAMtB,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,wBAAwB,GAC9B,UAAU,EAAE,CAsFd;AAMD,qBAAa,gBAAiB,YAAW,aAAa;IACpD,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAS;IAEpC,KAAK,CAAC,MAAM,EAAE,gBAAgB,GAAG,WAAW;IAI5C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,WAAW;IAIhE,OAAO,CAAC,YAAY;CA4DrB;AAoKD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Integration tests for Spring AI Provider
3
+ *
4
+ * Tests the full provider lifecycle using mock subprocess that emits
5
+ * Spring AI JSONL events, covering:
6
+ * - Happy path spawn + complete
7
+ * - Session resume
8
+ * - Error handling (missing JAR, missing Java, agent crash)
9
+ * - Cost data extraction accuracy
10
+ * - Tool permission adapter output
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=spring-ai-provider.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring-ai-provider.integration.test.d.ts","sourceRoot":"","sources":["../../../src/providers/spring-ai-provider.integration.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}