@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,148 @@
1
+ /**
2
+ * Route Manifest — Single source of truth for all AgentFactory route and page files.
3
+ *
4
+ * Used by `af-sync-routes` to generate missing route files in consumer projects,
5
+ * and by parity tests to verify create-app templates stay aligned.
6
+ */
7
+ export const ROUTE_MANIFEST = {
8
+ version: 1,
9
+ routes: [
10
+ // Webhook & OAuth
11
+ {
12
+ path: 'src/app/webhook/route.ts',
13
+ methods: { POST: 'routes.webhook.POST', GET: 'routes.webhook.GET' },
14
+ },
15
+ {
16
+ path: 'src/app/callback/route.ts',
17
+ methods: { GET: 'routes.oauth.callback.GET' },
18
+ },
19
+ // Worker routes
20
+ {
21
+ path: 'src/app/api/workers/register/route.ts',
22
+ methods: { POST: 'routes.workers.register.POST' },
23
+ },
24
+ {
25
+ path: 'src/app/api/workers/route.ts',
26
+ methods: { GET: 'routes.workers.list.GET' },
27
+ },
28
+ {
29
+ path: 'src/app/api/workers/[id]/route.ts',
30
+ methods: { GET: 'routes.workers.detail.GET', DELETE: 'routes.workers.detail.DELETE' },
31
+ },
32
+ {
33
+ path: 'src/app/api/workers/[id]/heartbeat/route.ts',
34
+ methods: { POST: 'routes.workers.heartbeat.POST' },
35
+ },
36
+ {
37
+ path: 'src/app/api/workers/[id]/poll/route.ts',
38
+ methods: { GET: 'routes.workers.poll.GET' },
39
+ },
40
+ // Session routes
41
+ {
42
+ path: 'src/app/api/sessions/route.ts',
43
+ methods: { GET: 'routes.sessions.list.GET' },
44
+ },
45
+ {
46
+ path: 'src/app/api/sessions/[id]/route.ts',
47
+ methods: { GET: 'routes.sessions.detail.GET' },
48
+ },
49
+ {
50
+ path: 'src/app/api/sessions/[id]/claim/route.ts',
51
+ methods: { POST: 'routes.sessions.claim.POST' },
52
+ },
53
+ {
54
+ path: 'src/app/api/sessions/[id]/status/route.ts',
55
+ methods: { POST: 'routes.sessions.status.POST', GET: 'routes.sessions.status.GET' },
56
+ },
57
+ {
58
+ path: 'src/app/api/sessions/[id]/lock-refresh/route.ts',
59
+ methods: { POST: 'routes.sessions.lockRefresh.POST' },
60
+ },
61
+ {
62
+ path: 'src/app/api/sessions/[id]/prompts/route.ts',
63
+ methods: { POST: 'routes.sessions.prompts.POST', GET: 'routes.sessions.prompts.GET' },
64
+ },
65
+ {
66
+ path: 'src/app/api/sessions/[id]/transfer-ownership/route.ts',
67
+ methods: { POST: 'routes.sessions.transferOwnership.POST' },
68
+ },
69
+ {
70
+ path: 'src/app/api/sessions/[id]/activity/route.ts',
71
+ methods: { POST: 'routes.sessions.activity.POST' },
72
+ },
73
+ {
74
+ path: 'src/app/api/sessions/[id]/completion/route.ts',
75
+ methods: { POST: 'routes.sessions.completion.POST' },
76
+ },
77
+ {
78
+ path: 'src/app/api/sessions/[id]/external-urls/route.ts',
79
+ methods: { POST: 'routes.sessions.externalUrls.POST' },
80
+ },
81
+ {
82
+ path: 'src/app/api/sessions/[id]/progress/route.ts',
83
+ methods: { POST: 'routes.sessions.progress.POST' },
84
+ },
85
+ {
86
+ path: 'src/app/api/sessions/[id]/tool-error/route.ts',
87
+ methods: { POST: 'routes.sessions.toolError.POST' },
88
+ },
89
+ // Public routes
90
+ {
91
+ path: 'src/app/api/public/stats/route.ts',
92
+ methods: { GET: 'routes.public.stats.GET' },
93
+ },
94
+ {
95
+ path: 'src/app/api/public/sessions/route.ts',
96
+ methods: { GET: 'routes.public.sessions.GET' },
97
+ },
98
+ {
99
+ path: 'src/app/api/public/sessions/[id]/route.ts',
100
+ methods: { GET: 'routes.public.sessionDetail.GET' },
101
+ },
102
+ // Config route
103
+ {
104
+ path: 'src/app/api/config/route.ts',
105
+ methods: { GET: 'routes.config.GET' },
106
+ },
107
+ // Cleanup route
108
+ {
109
+ path: 'src/app/api/cleanup/route.ts',
110
+ methods: { POST: 'routes.cleanup.POST', GET: 'routes.cleanup.GET' },
111
+ },
112
+ // Issue tracker proxy (centralized API gateway for agents/governors)
113
+ {
114
+ path: 'src/app/api/issue-tracker-proxy/route.ts',
115
+ methods: { POST: 'routes.issueTrackerProxy.POST', GET: 'routes.issueTrackerProxy.GET' },
116
+ },
117
+ ],
118
+ pages: [
119
+ {
120
+ path: 'src/app/page.tsx',
121
+ component: 'DashboardPage',
122
+ exportName: 'DashboardPage',
123
+ importAlias: 'DashboardPage as FleetPage',
124
+ },
125
+ {
126
+ path: 'src/app/pipeline/page.tsx',
127
+ component: 'PipelinePage',
128
+ exportName: 'Pipeline',
129
+ },
130
+ {
131
+ path: 'src/app/sessions/page.tsx',
132
+ component: 'SessionPage',
133
+ exportName: 'Sessions',
134
+ },
135
+ {
136
+ path: 'src/app/sessions/[id]/page.tsx',
137
+ component: 'SessionPage',
138
+ exportName: 'SessionDetailPage',
139
+ params: ['id'],
140
+ propMapping: { id: 'sessionId' },
141
+ },
142
+ {
143
+ path: 'src/app/settings/page.tsx',
144
+ component: 'SettingsPage',
145
+ exportName: 'Settings',
146
+ },
147
+ ],
148
+ };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Linear Activity Emitter
3
+ *
4
+ * Emits Claude stream events to Linear as agent activities.
5
+ * Handles rate limiting by batching rapid activities and
6
+ * truncating long outputs.
7
+ *
8
+ * Mapping:
9
+ * - assistant message → response (persisted, user-directed communication)
10
+ * - tool_use → action (ephemeral)
11
+ * - tool_result → action (ephemeral)
12
+ * - result → response (persisted)
13
+ * - error → error (persisted)
14
+ */
15
+ import type { AgentSession } from '@renseiai/agentfactory-linear';
16
+ /** Configuration for the activity emitter */
17
+ export interface ActivityEmitterConfig {
18
+ /** AgentSession to emit activities to */
19
+ session: AgentSession;
20
+ /** Minimum interval between activities in ms (default: 500ms) */
21
+ minInterval?: number;
22
+ /** Maximum length for tool outputs before truncation (default: 2000) */
23
+ maxOutputLength?: number;
24
+ /** Whether to include timestamps in activities (default: false) */
25
+ includeTimestamps?: boolean;
26
+ /** Optional callback when an activity is emitted */
27
+ onActivityEmitted?: (type: string, content: string) => void;
28
+ /** Optional callback when an activity is throttled */
29
+ onActivityThrottled?: (type: string, content: string) => void;
30
+ }
31
+ /**
32
+ * Activity Emitter
33
+ *
34
+ * Handles rate-limited emission of Claude events to Linear activities.
35
+ */
36
+ export declare class ActivityEmitter {
37
+ private readonly session;
38
+ private readonly minInterval;
39
+ private readonly maxOutputLength;
40
+ private readonly includeTimestamps;
41
+ private readonly onActivityEmitted?;
42
+ private readonly onActivityThrottled?;
43
+ private lastEmitTime;
44
+ private queue;
45
+ private flushTimer;
46
+ private isProcessing;
47
+ private readonly reportedToolErrors;
48
+ constructor(config: ActivityEmitterConfig);
49
+ /**
50
+ * Emit a thought activity (persistent by default for visibility in Linear)
51
+ */
52
+ emitThought(content: string, ephemeral?: boolean): Promise<void>;
53
+ /**
54
+ * Emit a tool use activity (ephemeral by default)
55
+ */
56
+ emitToolUse(tool: string, input: Record<string, unknown>, ephemeral?: boolean): Promise<void>;
57
+ /**
58
+ * Emit a response activity (persisted)
59
+ */
60
+ emitResponse(content: string): Promise<void>;
61
+ /**
62
+ * Emit an error activity (persisted)
63
+ */
64
+ emitError(error: Error | string): Promise<void>;
65
+ /**
66
+ * Report a tool error as a Linear issue for tracking and improvement.
67
+ * Creates a bug in the Agent project backlog.
68
+ *
69
+ * @param toolName - Name of the tool that errored
70
+ * @param errorMessage - The error message
71
+ * @param context - Additional context about the error
72
+ * @returns The created issue, or null if creation failed or was deduplicated
73
+ */
74
+ reportToolError(toolName: string, errorMessage: string, context?: {
75
+ issueIdentifier?: string;
76
+ additionalContext?: Record<string, unknown>;
77
+ }): Promise<{
78
+ id: string;
79
+ identifier: string;
80
+ url: string;
81
+ } | null>;
82
+ /**
83
+ * Queue an activity for emission with rate limiting
84
+ */
85
+ private queueActivity;
86
+ /**
87
+ * Process queued activities
88
+ */
89
+ private processQueue;
90
+ /**
91
+ * Merge consecutive similar activities in the queue
92
+ */
93
+ private mergeQueuedActivities;
94
+ /**
95
+ * Emit a single activity to Linear
96
+ */
97
+ private emitActivity;
98
+ /**
99
+ * Summarize tool input for display
100
+ */
101
+ private summarizeToolInput;
102
+ /**
103
+ * Truncate long output strings
104
+ */
105
+ private truncateOutput;
106
+ /**
107
+ * Flush all pending activities immediately
108
+ */
109
+ flush(): Promise<void>;
110
+ /**
111
+ * Helper delay function
112
+ */
113
+ private delay;
114
+ }
115
+ /**
116
+ * Create an activity emitter instance
117
+ */
118
+ export declare function createActivityEmitter(config: ActivityEmitterConfig): ActivityEmitter;
119
+ //# sourceMappingURL=activity-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-emitter.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/activity-emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAGjE,6CAA6C;AAC7C,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,OAAO,EAAE,YAAY,CAAA;IACrB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3D,sDAAsD;IACtD,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9D;AAcD;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAyC;IAC5E,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAyC;IAE9E,OAAO,CAAC,YAAY,CAAI;IACxB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,YAAY,CAAQ;IAE5B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAyB;gBAEhD,MAAM,EAAE,qBAAqB;IASzC;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpE;;OAEG;IACG,WAAW,CACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,UAAO,GACf,OAAO,CAAC,IAAI,CAAC;IAWhB;;OAEG;IACG,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlD;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASrD;;;;;;;;OAQG;IACG,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;QACR,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAC5C,GACA,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IA2BlE;;OAEG;YACW,aAAa;IAe3B;;OAEG;YACW,YAAY;IA+B1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiD7B;;OAEG;YACW,YAAY;IA6C1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoC1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,GAC5B,eAAe,CAEjB"}
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Linear Activity Emitter
3
+ *
4
+ * Emits Claude stream events to Linear as agent activities.
5
+ * Handles rate limiting by batching rapid activities and
6
+ * truncating long outputs.
7
+ *
8
+ * Mapping:
9
+ * - assistant message → response (persisted, user-directed communication)
10
+ * - tool_use → action (ephemeral)
11
+ * - tool_result → action (ephemeral)
12
+ * - result → response (persisted)
13
+ * - error → error (persisted)
14
+ */
15
+ import { ENVIRONMENT_ISSUE_TYPES } from '@renseiai/agentfactory-linear';
16
+ const DEFAULT_MIN_INTERVAL = 500;
17
+ const DEFAULT_MAX_OUTPUT_LENGTH = 2000;
18
+ /**
19
+ * Activity Emitter
20
+ *
21
+ * Handles rate-limited emission of Claude events to Linear activities.
22
+ */
23
+ export class ActivityEmitter {
24
+ session;
25
+ minInterval;
26
+ maxOutputLength;
27
+ includeTimestamps;
28
+ onActivityEmitted;
29
+ onActivityThrottled;
30
+ lastEmitTime = 0;
31
+ queue = [];
32
+ flushTimer = null;
33
+ isProcessing = false;
34
+ // Track reported tool error signatures for deduplication
35
+ reportedToolErrors = new Set();
36
+ constructor(config) {
37
+ this.session = config.session;
38
+ this.minInterval = config.minInterval ?? DEFAULT_MIN_INTERVAL;
39
+ this.maxOutputLength = config.maxOutputLength ?? DEFAULT_MAX_OUTPUT_LENGTH;
40
+ this.includeTimestamps = config.includeTimestamps ?? false;
41
+ this.onActivityEmitted = config.onActivityEmitted;
42
+ this.onActivityThrottled = config.onActivityThrottled;
43
+ }
44
+ /**
45
+ * Emit a thought activity (persistent by default for visibility in Linear)
46
+ */
47
+ async emitThought(content, ephemeral = false) {
48
+ await this.queueActivity({
49
+ type: 'thought',
50
+ content,
51
+ ephemeral,
52
+ });
53
+ }
54
+ /**
55
+ * Emit a tool use activity (ephemeral by default)
56
+ */
57
+ async emitToolUse(tool, input, ephemeral = true) {
58
+ const inputSummary = this.summarizeToolInput(tool, input);
59
+ await this.queueActivity({
60
+ type: 'action',
61
+ content: `${tool}: ${inputSummary}`,
62
+ ephemeral,
63
+ toolName: tool,
64
+ toolInput: input,
65
+ });
66
+ }
67
+ /**
68
+ * Emit a response activity (persisted)
69
+ */
70
+ async emitResponse(content) {
71
+ await this.queueActivity({
72
+ type: 'response',
73
+ content,
74
+ ephemeral: false,
75
+ });
76
+ }
77
+ /**
78
+ * Emit an error activity (persisted)
79
+ */
80
+ async emitError(error) {
81
+ const message = error instanceof Error ? error.message : error;
82
+ await this.queueActivity({
83
+ type: 'error',
84
+ content: message,
85
+ ephemeral: false,
86
+ });
87
+ }
88
+ /**
89
+ * Report a tool error as a Linear issue for tracking and improvement.
90
+ * Creates a bug in the Agent project backlog.
91
+ *
92
+ * @param toolName - Name of the tool that errored
93
+ * @param errorMessage - The error message
94
+ * @param context - Additional context about the error
95
+ * @returns The created issue, or null if creation failed or was deduplicated
96
+ */
97
+ async reportToolError(toolName, errorMessage, context) {
98
+ // Deduplicate using tool name + first 100 chars of error
99
+ const signature = `${toolName}:${errorMessage.substring(0, 100)}`;
100
+ if (this.reportedToolErrors.has(signature)) {
101
+ return null;
102
+ }
103
+ this.reportedToolErrors.add(signature);
104
+ try {
105
+ return await this.session.reportEnvironmentIssue(`Tool error: ${toolName}`, `The agent encountered an error while using the **${toolName}** tool.\n\n**Error:**\n\`\`\`\n${errorMessage}\n\`\`\``, {
106
+ issueType: ENVIRONMENT_ISSUE_TYPES.TOOL,
107
+ sourceIssueId: context?.issueIdentifier,
108
+ additionalContext: {
109
+ toolName,
110
+ ...context?.additionalContext,
111
+ },
112
+ });
113
+ }
114
+ catch (error) {
115
+ console.error('[ActivityEmitter] Failed to report tool error:', error);
116
+ return null;
117
+ }
118
+ }
119
+ /**
120
+ * Queue an activity for emission with rate limiting
121
+ */
122
+ async queueActivity(activity) {
123
+ this.queue.push(activity);
124
+ // Schedule flush if not already scheduled
125
+ if (!this.flushTimer && !this.isProcessing) {
126
+ const timeSinceLastEmit = Date.now() - this.lastEmitTime;
127
+ const delay = Math.max(0, this.minInterval - timeSinceLastEmit);
128
+ this.flushTimer = setTimeout(() => {
129
+ this.flushTimer = null;
130
+ this.processQueue();
131
+ }, delay);
132
+ }
133
+ }
134
+ /**
135
+ * Process queued activities
136
+ */
137
+ async processQueue() {
138
+ if (this.isProcessing || this.queue.length === 0)
139
+ return;
140
+ this.isProcessing = true;
141
+ try {
142
+ // Merge similar consecutive activities to reduce API calls
143
+ const merged = this.mergeQueuedActivities();
144
+ for (const activity of merged) {
145
+ await this.emitActivity(activity);
146
+ this.lastEmitTime = Date.now();
147
+ // Small delay between emissions to avoid rate limits
148
+ if (merged.length > 1) {
149
+ await this.delay(100);
150
+ }
151
+ }
152
+ }
153
+ finally {
154
+ this.isProcessing = false;
155
+ // If more activities were queued during processing, schedule another flush
156
+ if (this.queue.length > 0 && !this.flushTimer) {
157
+ this.flushTimer = setTimeout(() => {
158
+ this.flushTimer = null;
159
+ this.processQueue();
160
+ }, this.minInterval);
161
+ }
162
+ }
163
+ }
164
+ /**
165
+ * Merge consecutive similar activities in the queue
166
+ */
167
+ mergeQueuedActivities() {
168
+ const activities = [...this.queue];
169
+ this.queue = [];
170
+ if (activities.length <= 1)
171
+ return activities;
172
+ const merged = [];
173
+ let current = activities[0];
174
+ for (let i = 1; i < activities.length; i++) {
175
+ const next = activities[i];
176
+ // Merge consecutive thoughts
177
+ if (current.type === 'thought' &&
178
+ next.type === 'thought' &&
179
+ current.ephemeral === next.ephemeral) {
180
+ current = {
181
+ ...current,
182
+ content: `${current.content}\n\n${next.content}`,
183
+ };
184
+ this.onActivityThrottled?.('thought', next.content);
185
+ continue;
186
+ }
187
+ // Merge consecutive tool results for same tool
188
+ if (current.type === 'action' &&
189
+ next.type === 'action' &&
190
+ current.toolName === next.toolName &&
191
+ current.ephemeral === next.ephemeral) {
192
+ current = {
193
+ ...current,
194
+ content: `${current.content}\n${next.content}`,
195
+ };
196
+ this.onActivityThrottled?.('action', next.content);
197
+ continue;
198
+ }
199
+ merged.push(current);
200
+ current = next;
201
+ }
202
+ merged.push(current);
203
+ return merged;
204
+ }
205
+ /**
206
+ * Emit a single activity to Linear
207
+ */
208
+ async emitActivity(activity) {
209
+ try {
210
+ const content = this.includeTimestamps
211
+ ? `[${new Date().toISOString()}] ${activity.content}`
212
+ : activity.content;
213
+ switch (activity.type) {
214
+ case 'thought':
215
+ await this.session.emitThought(content, activity.ephemeral);
216
+ break;
217
+ case 'action':
218
+ if (activity.toolName && activity.toolInput) {
219
+ await this.session.emitAction(activity.toolName, activity.toolInput, activity.ephemeral);
220
+ }
221
+ else if (activity.toolName && activity.toolOutput) {
222
+ await this.session.emitToolResult(activity.toolName, activity.toolOutput, activity.ephemeral);
223
+ }
224
+ else {
225
+ // Generic action - emit as thought
226
+ await this.session.emitThought(content, activity.ephemeral);
227
+ }
228
+ break;
229
+ case 'response':
230
+ await this.session.emitResponse(content);
231
+ break;
232
+ case 'error':
233
+ await this.session.emitError(new Error(content));
234
+ break;
235
+ }
236
+ this.onActivityEmitted?.(activity.type, content);
237
+ }
238
+ catch (error) {
239
+ console.error(`Failed to emit ${activity.type} activity:`, error);
240
+ }
241
+ }
242
+ /**
243
+ * Summarize tool input for display
244
+ */
245
+ summarizeToolInput(tool, input) {
246
+ // Tool-specific summaries
247
+ switch (tool) {
248
+ case 'Read':
249
+ return String(input.file_path || input.path || 'file');
250
+ case 'Write':
251
+ return String(input.file_path || input.path || 'file');
252
+ case 'Edit':
253
+ return String(input.file_path || input.path || 'file');
254
+ case 'Grep':
255
+ return `"${input.pattern}" in ${input.path || '.'}`;
256
+ case 'Glob':
257
+ return String(input.pattern || '*');
258
+ case 'Bash':
259
+ const cmd = String(input.command || '');
260
+ return cmd.length > 50 ? cmd.substring(0, 47) + '...' : cmd;
261
+ case 'Task':
262
+ return String(input.description || input.prompt || 'task');
263
+ default:
264
+ // Generic: show first string value or truncated JSON
265
+ const firstStringValue = Object.values(input).find((v) => typeof v === 'string');
266
+ if (firstStringValue) {
267
+ return firstStringValue.length > 50
268
+ ? firstStringValue.substring(0, 47) + '...'
269
+ : firstStringValue;
270
+ }
271
+ const json = JSON.stringify(input);
272
+ return json.length > 50 ? json.substring(0, 47) + '...' : json;
273
+ }
274
+ }
275
+ /**
276
+ * Truncate long output strings
277
+ */
278
+ truncateOutput(output) {
279
+ if (output.length <= this.maxOutputLength)
280
+ return output;
281
+ return (output.substring(0, this.maxOutputLength) +
282
+ `\n\n... (truncated ${output.length - this.maxOutputLength} chars)`);
283
+ }
284
+ /**
285
+ * Flush all pending activities immediately
286
+ */
287
+ async flush() {
288
+ if (this.flushTimer) {
289
+ clearTimeout(this.flushTimer);
290
+ this.flushTimer = null;
291
+ }
292
+ await this.processQueue();
293
+ }
294
+ /**
295
+ * Helper delay function
296
+ */
297
+ delay(ms) {
298
+ return new Promise((resolve) => setTimeout(resolve, ms));
299
+ }
300
+ }
301
+ /**
302
+ * Create an activity emitter instance
303
+ */
304
+ export function createActivityEmitter(config) {
305
+ return new ActivityEmitter(config);
306
+ }