@penclipai/server 2026.704.0 → 2026.714.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 (485) hide show
  1. package/dist/adapters/index.d.ts +1 -1
  2. package/dist/adapters/index.d.ts.map +1 -1
  3. package/dist/adapters/index.js.map +1 -1
  4. package/dist/adapters/process/execute.d.ts.map +1 -1
  5. package/dist/adapters/process/execute.js +1 -0
  6. package/dist/adapters/process/execute.js.map +1 -1
  7. package/dist/adapters/registry.d.ts.map +1 -1
  8. package/dist/adapters/registry.js +79 -51
  9. package/dist/adapters/registry.js.map +1 -1
  10. package/dist/adapters/utils.d.ts +5 -0
  11. package/dist/adapters/utils.d.ts.map +1 -1
  12. package/dist/adapters/utils.js.map +1 -1
  13. package/dist/agent-auth-jwt.d.ts +5 -1
  14. package/dist/agent-auth-jwt.d.ts.map +1 -1
  15. package/dist/agent-auth-jwt.js +72 -20
  16. package/dist/agent-auth-jwt.js.map +1 -1
  17. package/dist/app.d.ts +2 -0
  18. package/dist/app.d.ts.map +1 -1
  19. package/dist/app.js +10 -0
  20. package/dist/app.js.map +1 -1
  21. package/dist/built-ins/agents/reflection-coach/AGENTS.md +47 -0
  22. package/dist/built-ins/agents/reflection-coach/routines/recent-agent-reflection.md +77 -0
  23. package/dist/errors.d.ts +1 -1
  24. package/dist/errors.d.ts.map +1 -1
  25. package/dist/errors.js +2 -2
  26. package/dist/errors.js.map +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +208 -116
  29. package/dist/index.js.map +1 -1
  30. package/dist/middleware/api-compression.d.ts +8 -0
  31. package/dist/middleware/api-compression.d.ts.map +1 -0
  32. package/dist/middleware/api-compression.js +207 -0
  33. package/dist/middleware/api-compression.js.map +1 -0
  34. package/dist/middleware/auth.d.ts.map +1 -1
  35. package/dist/middleware/auth.js +130 -3
  36. package/dist/middleware/auth.js.map +1 -1
  37. package/dist/middleware/error-handler.d.ts.map +1 -1
  38. package/dist/middleware/error-handler.js +27 -0
  39. package/dist/middleware/error-handler.js.map +1 -1
  40. package/dist/onboarding-assets/default/AGENTS.md +1 -0
  41. package/dist/redaction.d.ts.map +1 -1
  42. package/dist/redaction.js +11 -0
  43. package/dist/redaction.js.map +1 -1
  44. package/dist/routes/access.d.ts.map +1 -1
  45. package/dist/routes/access.js +4 -3
  46. package/dist/routes/access.js.map +1 -1
  47. package/dist/routes/adapters.d.ts.map +1 -1
  48. package/dist/routes/adapters.js +2 -0
  49. package/dist/routes/adapters.js.map +1 -1
  50. package/dist/routes/agents.d.ts.map +1 -1
  51. package/dist/routes/agents.js +222 -87
  52. package/dist/routes/agents.js.map +1 -1
  53. package/dist/routes/attention.d.ts +3 -0
  54. package/dist/routes/attention.d.ts.map +1 -0
  55. package/dist/routes/attention.js +24 -0
  56. package/dist/routes/attention.js.map +1 -0
  57. package/dist/routes/authz.d.ts.map +1 -1
  58. package/dist/routes/authz.js +29 -1
  59. package/dist/routes/authz.js.map +1 -1
  60. package/dist/routes/board-chat.d.ts.map +1 -1
  61. package/dist/routes/board-chat.js +4 -1
  62. package/dist/routes/board-chat.js.map +1 -1
  63. package/dist/routes/built-in-agents.d.ts +3 -0
  64. package/dist/routes/built-in-agents.d.ts.map +1 -0
  65. package/dist/routes/built-in-agents.js +267 -0
  66. package/dist/routes/built-in-agents.js.map +1 -0
  67. package/dist/routes/cases.d.ts +46 -0
  68. package/dist/routes/cases.d.ts.map +1 -0
  69. package/dist/routes/cases.js +1395 -0
  70. package/dist/routes/cases.js.map +1 -0
  71. package/dist/routes/companies.d.ts.map +1 -1
  72. package/dist/routes/companies.js +4 -1
  73. package/dist/routes/companies.js.map +1 -1
  74. package/dist/routes/company-skills.d.ts.map +1 -1
  75. package/dist/routes/company-skills.js +453 -33
  76. package/dist/routes/company-skills.js.map +1 -1
  77. package/dist/routes/environments.d.ts.map +1 -1
  78. package/dist/routes/environments.js +71 -8
  79. package/dist/routes/environments.js.map +1 -1
  80. package/dist/routes/execution-workspaces.d.ts.map +1 -1
  81. package/dist/routes/execution-workspaces.js +89 -3
  82. package/dist/routes/execution-workspaces.js.map +1 -1
  83. package/dist/routes/health.d.ts +2 -0
  84. package/dist/routes/health.d.ts.map +1 -1
  85. package/dist/routes/health.js +30 -0
  86. package/dist/routes/health.js.map +1 -1
  87. package/dist/routes/inbox-dismissals.d.ts.map +1 -1
  88. package/dist/routes/inbox-dismissals.js +80 -19
  89. package/dist/routes/inbox-dismissals.js.map +1 -1
  90. package/dist/routes/index.d.ts +2 -0
  91. package/dist/routes/index.d.ts.map +1 -1
  92. package/dist/routes/index.js +2 -0
  93. package/dist/routes/index.js.map +1 -1
  94. package/dist/routes/issues.d.ts +25 -0
  95. package/dist/routes/issues.d.ts.map +1 -1
  96. package/dist/routes/issues.js +1455 -46
  97. package/dist/routes/issues.js.map +1 -1
  98. package/dist/routes/openapi.d.ts.map +1 -1
  99. package/dist/routes/openapi.js +448 -11
  100. package/dist/routes/openapi.js.map +1 -1
  101. package/dist/routes/pipelines.js +2 -2
  102. package/dist/routes/pipelines.js.map +1 -1
  103. package/dist/routes/resource-memberships.d.ts.map +1 -1
  104. package/dist/routes/resource-memberships.js +13 -5
  105. package/dist/routes/resource-memberships.js.map +1 -1
  106. package/dist/routes/secrets.d.ts.map +1 -1
  107. package/dist/routes/secrets.js +261 -1
  108. package/dist/routes/secrets.js.map +1 -1
  109. package/dist/routes/sidebar-badges.d.ts.map +1 -1
  110. package/dist/routes/sidebar-badges.js +18 -2
  111. package/dist/routes/sidebar-badges.js.map +1 -1
  112. package/dist/routes/user-profiles.d.ts.map +1 -1
  113. package/dist/routes/user-profiles.js +5 -4
  114. package/dist/routes/user-profiles.js.map +1 -1
  115. package/dist/server-info.d.ts +2 -0
  116. package/dist/server-info.d.ts.map +1 -1
  117. package/dist/server-info.js +20 -5
  118. package/dist/server-info.js.map +1 -1
  119. package/dist/services/access.d.ts +4 -4
  120. package/dist/services/access.d.ts.map +1 -1
  121. package/dist/services/activity.d.ts +3 -3
  122. package/dist/services/activity.d.ts.map +1 -1
  123. package/dist/services/activity.js +5 -4
  124. package/dist/services/activity.js.map +1 -1
  125. package/dist/services/adapter-registry-bootstrap.reconcile.test.js +1 -0
  126. package/dist/services/adapter-registry-bootstrap.reconcile.test.js.map +1 -1
  127. package/dist/services/agent-secret-bindings.d.ts +15 -0
  128. package/dist/services/agent-secret-bindings.d.ts.map +1 -1
  129. package/dist/services/agent-secret-bindings.js +43 -0
  130. package/dist/services/agent-secret-bindings.js.map +1 -1
  131. package/dist/services/agents.d.ts +194 -133
  132. package/dist/services/agents.d.ts.map +1 -1
  133. package/dist/services/agents.js +107 -4
  134. package/dist/services/agents.js.map +1 -1
  135. package/dist/services/approvals.d.ts +10 -10
  136. package/dist/services/approvals.d.ts.map +1 -1
  137. package/dist/services/approvals.js +9 -1
  138. package/dist/services/approvals.js.map +1 -1
  139. package/dist/services/assets.d.ts +5 -5
  140. package/dist/services/attention.d.ts +11 -0
  141. package/dist/services/attention.d.ts.map +1 -0
  142. package/dist/services/attention.js +1024 -0
  143. package/dist/services/attention.js.map +1 -0
  144. package/dist/services/authorization.d.ts +15 -2
  145. package/dist/services/authorization.d.ts.map +1 -1
  146. package/dist/services/authorization.js +324 -8
  147. package/dist/services/authorization.js.map +1 -1
  148. package/dist/services/board-auth.d.ts +2 -2
  149. package/dist/services/budgets.d.ts.map +1 -1
  150. package/dist/services/budgets.js +8 -7
  151. package/dist/services/budgets.js.map +1 -1
  152. package/dist/services/built-in-agent-metadata.d.ts +9 -0
  153. package/dist/services/built-in-agent-metadata.d.ts.map +1 -0
  154. package/dist/services/built-in-agent-metadata.js +39 -0
  155. package/dist/services/built-in-agent-metadata.js.map +1 -0
  156. package/dist/services/built-in-agents.d.ts +394 -0
  157. package/dist/services/built-in-agents.d.ts.map +1 -0
  158. package/dist/services/built-in-agents.js +1426 -0
  159. package/dist/services/built-in-agents.js.map +1 -0
  160. package/dist/services/change-consent-gate.d.ts +18 -0
  161. package/dist/services/change-consent-gate.d.ts.map +1 -0
  162. package/dist/services/change-consent-gate.js +170 -0
  163. package/dist/services/change-consent-gate.js.map +1 -0
  164. package/dist/services/companies.d.ts +14 -8
  165. package/dist/services/companies.d.ts.map +1 -1
  166. package/dist/services/companies.js +6 -1
  167. package/dist/services/companies.js.map +1 -1
  168. package/dist/services/company-artifacts.d.ts +4 -1
  169. package/dist/services/company-artifacts.d.ts.map +1 -1
  170. package/dist/services/company-artifacts.js +9 -1
  171. package/dist/services/company-artifacts.js.map +1 -1
  172. package/dist/services/company-member-roles.d.ts.map +1 -1
  173. package/dist/services/company-member-roles.js +2 -0
  174. package/dist/services/company-member-roles.js.map +1 -1
  175. package/dist/services/company-portability.d.ts +1 -1
  176. package/dist/services/company-portability.d.ts.map +1 -1
  177. package/dist/services/company-portability.js +113 -8
  178. package/dist/services/company-portability.js.map +1 -1
  179. package/dist/services/company-search.d.ts.map +1 -1
  180. package/dist/services/company-search.js +843 -294
  181. package/dist/services/company-search.js.map +1 -1
  182. package/dist/services/company-skills.d.ts +64 -3
  183. package/dist/services/company-skills.d.ts.map +1 -1
  184. package/dist/services/company-skills.js +1205 -20
  185. package/dist/services/company-skills.js.map +1 -1
  186. package/dist/services/costs.d.ts +9 -8
  187. package/dist/services/costs.d.ts.map +1 -1
  188. package/dist/services/costs.js +9 -2
  189. package/dist/services/costs.js.map +1 -1
  190. package/dist/services/dashboard.d.ts +2 -0
  191. package/dist/services/dashboard.d.ts.map +1 -1
  192. package/dist/services/dashboard.js +60 -17
  193. package/dist/services/dashboard.js.map +1 -1
  194. package/dist/services/database-backup-health.d.ts +34 -0
  195. package/dist/services/database-backup-health.d.ts.map +1 -0
  196. package/dist/services/database-backup-health.js +104 -0
  197. package/dist/services/database-backup-health.js.map +1 -0
  198. package/dist/services/document-annotations.d.ts +169 -1
  199. package/dist/services/document-annotations.d.ts.map +1 -1
  200. package/dist/services/document-annotations.js +272 -1
  201. package/dist/services/document-annotations.js.map +1 -1
  202. package/dist/services/documents.d.ts +368 -0
  203. package/dist/services/documents.d.ts.map +1 -1
  204. package/dist/services/documents.js +2 -2
  205. package/dist/services/documents.js.map +1 -1
  206. package/dist/services/environment-config.d.ts.map +1 -1
  207. package/dist/services/environment-config.js +6 -0
  208. package/dist/services/environment-config.js.map +1 -1
  209. package/dist/services/environment-custom-image-runtime.d.ts +28 -0
  210. package/dist/services/environment-custom-image-runtime.d.ts.map +1 -1
  211. package/dist/services/environment-custom-image-runtime.js +106 -7
  212. package/dist/services/environment-custom-image-runtime.js.map +1 -1
  213. package/dist/services/environment-custom-images.d.ts +31 -1
  214. package/dist/services/environment-custom-images.d.ts.map +1 -1
  215. package/dist/services/environment-custom-images.js +110 -4
  216. package/dist/services/environment-custom-images.js.map +1 -1
  217. package/dist/services/environment-execution-target.d.ts.map +1 -1
  218. package/dist/services/environment-execution-target.js +1 -3
  219. package/dist/services/environment-execution-target.js.map +1 -1
  220. package/dist/services/environment-probe.d.ts +1 -0
  221. package/dist/services/environment-probe.d.ts.map +1 -1
  222. package/dist/services/environment-probe.js +99 -5
  223. package/dist/services/environment-probe.js.map +1 -1
  224. package/dist/services/environments.d.ts +3 -1
  225. package/dist/services/environments.d.ts.map +1 -1
  226. package/dist/services/environments.js +98 -3
  227. package/dist/services/environments.js.map +1 -1
  228. package/dist/services/execution-workspace-policy.d.ts +29 -3
  229. package/dist/services/execution-workspace-policy.d.ts.map +1 -1
  230. package/dist/services/execution-workspace-policy.js +44 -1
  231. package/dist/services/execution-workspace-policy.js.map +1 -1
  232. package/dist/services/execution-workspaces.d.ts +64 -1
  233. package/dist/services/execution-workspaces.d.ts.map +1 -1
  234. package/dist/services/execution-workspaces.js +634 -3
  235. package/dist/services/execution-workspaces.js.map +1 -1
  236. package/dist/services/external-objects.d.ts +26 -26
  237. package/dist/services/feedback.d.ts +2 -2
  238. package/dist/services/finance.d.ts +5 -5
  239. package/dist/services/goals.d.ts +8 -8
  240. package/dist/services/heartbeat-stop-metadata.d.ts +2 -2
  241. package/dist/services/heartbeat-stop-metadata.d.ts.map +1 -1
  242. package/dist/services/heartbeat-stop-metadata.js +4 -0
  243. package/dist/services/heartbeat-stop-metadata.js.map +1 -1
  244. package/dist/services/heartbeat-stop-metadata.test.js +9 -0
  245. package/dist/services/heartbeat-stop-metadata.test.js.map +1 -1
  246. package/dist/services/heartbeat.d.ts +133 -28
  247. package/dist/services/heartbeat.d.ts.map +1 -1
  248. package/dist/services/heartbeat.js +1963 -239
  249. package/dist/services/heartbeat.js.map +1 -1
  250. package/dist/services/inbox-dismissals.d.ts +26 -0
  251. package/dist/services/inbox-dismissals.d.ts.map +1 -1
  252. package/dist/services/inbox-dismissals.js +33 -18
  253. package/dist/services/inbox-dismissals.js.map +1 -1
  254. package/dist/services/index.d.ts +3 -1
  255. package/dist/services/index.d.ts.map +1 -1
  256. package/dist/services/index.js +3 -1
  257. package/dist/services/index.js.map +1 -1
  258. package/dist/services/instance-settings.d.ts +25 -1
  259. package/dist/services/instance-settings.d.ts.map +1 -1
  260. package/dist/services/instance-settings.js +103 -5
  261. package/dist/services/instance-settings.js.map +1 -1
  262. package/dist/services/issue-continuation-summary.js +1 -1
  263. package/dist/services/issue-continuation-summary.js.map +1 -1
  264. package/dist/services/issue-recovery-actions.d.ts +3 -0
  265. package/dist/services/issue-recovery-actions.d.ts.map +1 -1
  266. package/dist/services/issue-recovery-actions.js +9 -0
  267. package/dist/services/issue-recovery-actions.js.map +1 -1
  268. package/dist/services/issue-rewake-throttle.d.ts +92 -0
  269. package/dist/services/issue-rewake-throttle.d.ts.map +1 -0
  270. package/dist/services/issue-rewake-throttle.js +139 -0
  271. package/dist/services/issue-rewake-throttle.js.map +1 -0
  272. package/dist/services/issue-thread-interactions.d.ts +8 -1
  273. package/dist/services/issue-thread-interactions.d.ts.map +1 -1
  274. package/dist/services/issue-thread-interactions.js +231 -16
  275. package/dist/services/issue-thread-interactions.js.map +1 -1
  276. package/dist/services/issue-visibility.d.ts +4 -0
  277. package/dist/services/issue-visibility.d.ts.map +1 -0
  278. package/dist/services/issue-visibility.js +9 -0
  279. package/dist/services/issue-visibility.js.map +1 -0
  280. package/dist/services/issues.d.ts +225 -105
  281. package/dist/services/issues.d.ts.map +1 -1
  282. package/dist/services/issues.js +540 -18
  283. package/dist/services/issues.js.map +1 -1
  284. package/dist/services/local-service-supervisor.d.ts +3 -0
  285. package/dist/services/local-service-supervisor.d.ts.map +1 -1
  286. package/dist/services/local-service-supervisor.js +51 -0
  287. package/dist/services/local-service-supervisor.js.map +1 -1
  288. package/dist/services/pipeline-case-outputs.d.ts.map +1 -1
  289. package/dist/services/pipeline-case-outputs.js +2 -1
  290. package/dist/services/pipeline-case-outputs.js.map +1 -1
  291. package/dist/services/pipelines-aggregation.d.ts.map +1 -1
  292. package/dist/services/pipelines-aggregation.js +3 -2
  293. package/dist/services/pipelines-aggregation.js.map +1 -1
  294. package/dist/services/pipelines.d.ts +165 -165
  295. package/dist/services/pipelines.d.ts.map +1 -1
  296. package/dist/services/pipelines.js +6 -4
  297. package/dist/services/pipelines.js.map +1 -1
  298. package/dist/services/plugin-database.d.ts +2 -2
  299. package/dist/services/plugin-environment-driver.d.ts +1 -1
  300. package/dist/services/plugin-host-services.d.ts.map +1 -1
  301. package/dist/services/plugin-host-services.js +3 -1
  302. package/dist/services/plugin-host-services.js.map +1 -1
  303. package/dist/services/plugin-managed-routines.d.ts +1 -0
  304. package/dist/services/plugin-managed-routines.d.ts.map +1 -1
  305. package/dist/services/plugin-registry.d.ts +21 -21
  306. package/dist/services/productivity-review.d.ts +1 -0
  307. package/dist/services/productivity-review.d.ts.map +1 -1
  308. package/dist/services/productivity-review.js +6 -5
  309. package/dist/services/productivity-review.js.map +1 -1
  310. package/dist/services/projects.d.ts +9 -9
  311. package/dist/services/recovery/service.d.ts +82 -54
  312. package/dist/services/recovery/service.d.ts.map +1 -1
  313. package/dist/services/recovery/service.js +200 -35
  314. package/dist/services/recovery/service.js.map +1 -1
  315. package/dist/services/recovery/successful-run-handoff.d.ts +1 -0
  316. package/dist/services/recovery/successful-run-handoff.d.ts.map +1 -1
  317. package/dist/services/recovery/successful-run-handoff.js +2 -0
  318. package/dist/services/recovery/successful-run-handoff.js.map +1 -1
  319. package/dist/services/recovery/successful-run-handoff.test.js +20 -0
  320. package/dist/services/recovery/successful-run-handoff.test.js.map +1 -1
  321. package/dist/services/resource-memberships.d.ts +13 -10
  322. package/dist/services/resource-memberships.d.ts.map +1 -1
  323. package/dist/services/resource-memberships.js +89 -20
  324. package/dist/services/resource-memberships.js.map +1 -1
  325. package/dist/services/responsible-user-denial-run-outcomes.d.ts +60 -0
  326. package/dist/services/responsible-user-denial-run-outcomes.d.ts.map +1 -0
  327. package/dist/services/responsible-user-denial-run-outcomes.js +56 -0
  328. package/dist/services/responsible-user-denial-run-outcomes.js.map +1 -0
  329. package/dist/services/responsible-user-denial-run-outcomes.test.d.ts +2 -0
  330. package/dist/services/responsible-user-denial-run-outcomes.test.d.ts.map +1 -0
  331. package/dist/services/responsible-user-denial-run-outcomes.test.js +75 -0
  332. package/dist/services/responsible-user-denial-run-outcomes.test.js.map +1 -0
  333. package/dist/services/routines.d.ts +30 -8
  334. package/dist/services/routines.d.ts.map +1 -1
  335. package/dist/services/routines.js +241 -18
  336. package/dist/services/routines.js.map +1 -1
  337. package/dist/services/run-liveness.d.ts.map +1 -1
  338. package/dist/services/run-liveness.js +21 -0
  339. package/dist/services/run-liveness.js.map +1 -1
  340. package/dist/services/run-log-store.d.ts +1 -0
  341. package/dist/services/run-log-store.d.ts.map +1 -1
  342. package/dist/services/run-log-store.js +4 -0
  343. package/dist/services/run-log-store.js.map +1 -1
  344. package/dist/services/run-scratch.d.ts +42 -0
  345. package/dist/services/run-scratch.d.ts.map +1 -0
  346. package/dist/services/run-scratch.js +111 -0
  347. package/dist/services/run-scratch.js.map +1 -0
  348. package/dist/services/run-scratch.test.d.ts +2 -0
  349. package/dist/services/run-scratch.test.d.ts.map +1 -0
  350. package/dist/services/run-scratch.test.js +98 -0
  351. package/dist/services/run-scratch.test.js.map +1 -0
  352. package/dist/services/secrets.d.ts +1261 -64
  353. package/dist/services/secrets.d.ts.map +1 -1
  354. package/dist/services/secrets.js +1089 -96
  355. package/dist/services/secrets.js.map +1 -1
  356. package/dist/services/task-watchdogs.d.ts +1 -0
  357. package/dist/services/task-watchdogs.d.ts.map +1 -1
  358. package/dist/services/task-watchdogs.js +78 -9
  359. package/dist/services/task-watchdogs.js.map +1 -1
  360. package/dist/services/work-timeline.d.ts.map +1 -1
  361. package/dist/services/work-timeline.js +34 -2
  362. package/dist/services/work-timeline.js.map +1 -1
  363. package/dist/services/workspace-runtime-read-model.d.ts +30 -29
  364. package/dist/services/workspace-runtime-read-model.d.ts.map +1 -1
  365. package/dist/services/workspace-runtime-read-model.js.map +1 -1
  366. package/dist/services/workspace-runtime.d.ts +59 -13
  367. package/dist/services/workspace-runtime.d.ts.map +1 -1
  368. package/dist/services/workspace-runtime.js +1121 -102
  369. package/dist/services/workspace-runtime.js.map +1 -1
  370. package/dist/skills-catalog/catalog/bundled/paperclip-operations/reflection-coach/SKILL.md +202 -0
  371. package/dist/skills-catalog/catalog/bundled/product/paperclip-capsules/SKILL.md +1 -1
  372. package/dist/skills-catalog/catalog/bundled/product/wireframe/SKILL.md +1 -1
  373. package/dist/skills-catalog/catalog/optional/content/release-announcement/SKILL.md +90 -0
  374. package/dist/skills-catalog/catalog/optional/finance/ramp/SKILL.md +98 -0
  375. package/dist/skills-catalog/generated/catalog.json +84 -12
  376. package/dist/ui-branding.d.ts +7 -0
  377. package/dist/ui-branding.d.ts.map +1 -1
  378. package/dist/ui-branding.js +8 -2
  379. package/dist/ui-branding.js.map +1 -1
  380. package/dist/version.d.ts +14 -0
  381. package/dist/version.d.ts.map +1 -1
  382. package/dist/version.js +114 -3
  383. package/dist/version.js.map +1 -1
  384. package/package.json +19 -20
  385. package/skills/paperclip/SKILL.md +45 -10
  386. package/skills/paperclip/references/api-reference.md +246 -1
  387. package/skills/paperclip/references/cases.md +295 -0
  388. package/skills/paperclip/references/company-skills.md +1 -1
  389. package/skills/paperclip-board/SKILL.md +3 -4
  390. package/skills/paperclip-converting-plans-to-tasks/SKILL.md +3 -7
  391. package/skills/para-memory-files/SKILL.md +3 -7
  392. package/ui-dist/assets/{abnfDiagram-VRR7QNED-BsFz2IiG.js → abnfDiagram-VRR7QNED-Dtgfy1PK.js} +1 -1
  393. package/ui-dist/assets/{arc-HZhAwbOs.js → arc-BGdvNvs8.js} +1 -1
  394. package/ui-dist/assets/{architectureDiagram-ZJ3FMSHR-BteMjuOn.js → architectureDiagram-ZJ3FMSHR-CK19SQDx.js} +1 -1
  395. package/ui-dist/assets/{blockDiagram-677ZJIJ3-Iq66uZjf.js → blockDiagram-677ZJIJ3-Kh4N3XG4.js} +1 -1
  396. package/ui-dist/assets/{browser-ponyfill-BBsuyZJt.js → browser-ponyfill-B3hXtEFW.js} +1 -1
  397. package/ui-dist/assets/{c4Diagram-LMCZKHZV-_nlglj7I.js → c4Diagram-LMCZKHZV-CBHpGrgU.js} +1 -1
  398. package/ui-dist/assets/channel-4fjB8e8N.js +1 -0
  399. package/ui-dist/assets/{chunk-2Q5K7J3B-Cvz7WwSQ.js → chunk-2Q5K7J3B-BdHbqi7k.js} +1 -1
  400. package/ui-dist/assets/{chunk-32BRIVSS-LLubniCS.js → chunk-32BRIVSS-DxtzZzpt.js} +1 -1
  401. package/ui-dist/assets/{chunk-5VM5RSS4-BOst5hcr.js → chunk-5VM5RSS4-DMKxBbgu.js} +1 -1
  402. package/ui-dist/assets/{chunk-EX3LRPZG-D5WNShVm.js → chunk-EX3LRPZG-BaIOPi4v.js} +1 -1
  403. package/ui-dist/assets/{chunk-JWPE2WC7-CA07x4av.js → chunk-JWPE2WC7-DGo3MPmr.js} +1 -1
  404. package/ui-dist/assets/{chunk-MOJQB5TN-Clfi83rK.js → chunk-MOJQB5TN-BEhQg0uD.js} +1 -1
  405. package/ui-dist/assets/{chunk-RYQCIY6F-BhZ6p7YJ.js → chunk-RYQCIY6F-HPJ6zRpJ.js} +1 -1
  406. package/ui-dist/assets/{chunk-V7JOEXUC-CdexJGoV.js → chunk-V7JOEXUC-Bl_6cAJD.js} +1 -1
  407. package/ui-dist/assets/{chunk-VR4S4FIN-8vjmBhr1.js → chunk-VR4S4FIN-KMjgGCsw.js} +1 -1
  408. package/ui-dist/assets/{chunk-XXDRQBXY-CqmCaplj.js → chunk-XXDRQBXY-oWGAIKjr.js} +1 -1
  409. package/ui-dist/assets/classDiagram-OUVF2IWQ-CTXxO5l9.js +1 -0
  410. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-CTXxO5l9.js +1 -0
  411. package/ui-dist/assets/{cose-bilkent-JH36ORCC-CY-zAygY.js → cose-bilkent-JH36ORCC-Ckqse1pH.js} +1 -1
  412. package/ui-dist/assets/{cynefin-VYW2F7L2-BQSQ1HKr.js → cynefin-VYW2F7L2-DfZ8Hzqi.js} +1 -1
  413. package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-NJCuFrZL.js → cynefinDiagram-TSTJHNR4-BkDQo9oi.js} +1 -1
  414. package/ui-dist/assets/{dagre-VKFMJZFB-DAUPIc8g.js → dagre-VKFMJZFB-ClghXQ6E.js} +1 -1
  415. package/ui-dist/assets/{diagram-FQU43EPY-DvMwJlCi.js → diagram-FQU43EPY-D5a0CwpV.js} +1 -1
  416. package/ui-dist/assets/{diagram-G47NLZAW-DPY0Jz_y.js → diagram-G47NLZAW-hVjYR_xl.js} +1 -1
  417. package/ui-dist/assets/{diagram-NH7WQ7WH-BpopeEhp.js → diagram-NH7WQ7WH-BlDPgD5Z.js} +1 -1
  418. package/ui-dist/assets/{diagram-OA4YK3LP-Qpu05z9X.js → diagram-OA4YK3LP-D0iZKIS3.js} +1 -1
  419. package/ui-dist/assets/{diagram-WEI45ONY-DHnvw9XU.js → diagram-WEI45ONY-m6hrfD0J.js} +1 -1
  420. package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-D61S54_7.js → ebnfDiagram-CCIWWBDH-D4SQYLod.js} +1 -1
  421. package/ui-dist/assets/{erDiagram-Q63AITRT-pplAN_x2.js → erDiagram-Q63AITRT-Byzb6-I5.js} +1 -1
  422. package/ui-dist/assets/{flowDiagram-23GEKE2U-BaBcbyDq.js → flowDiagram-23GEKE2U-CaTUkFO6.js} +1 -1
  423. package/ui-dist/assets/{ganttDiagram-NO4QXBWP-BOJSII2b.js → ganttDiagram-NO4QXBWP-DmdMQ3ES.js} +1 -1
  424. package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-aYAaO4a2.js → gitGraphDiagram-IHSO6WYX-Bt-1g2CS.js} +1 -1
  425. package/ui-dist/assets/{index-CZxYajxF.js → index-2Dk9yO0W.js} +1 -1
  426. package/ui-dist/assets/{index-B8H0SHw1.js → index-8jLpgFNU.js} +1 -1
  427. package/ui-dist/assets/{index-3EKATXgc.js → index-AP_iimxs.js} +1 -1
  428. package/ui-dist/assets/{index-C2JgdjPa.js → index-BNJasQY9.js} +1 -1
  429. package/ui-dist/assets/{index-BaiskB3o.js → index-BO-aNmyX.js} +1 -1
  430. package/ui-dist/assets/{index-B5YenxAQ.js → index-BPCzCn1Y.js} +1 -1
  431. package/ui-dist/assets/{index-Da2kqT1M.js → index-BSLnLTb2.js} +1 -1
  432. package/ui-dist/assets/{index-By0oeEvz.js → index-CCZ2qgHN.js} +1 -1
  433. package/ui-dist/assets/{index-bUFCSEgv.js → index-CLZXR1k9.js} +1 -1
  434. package/ui-dist/assets/{index-CJlw4l9L.js → index-CTNfrE1s.js} +1 -1
  435. package/ui-dist/assets/{index-TmpY6Xh_.js → index-ChNd25s7.js} +1 -1
  436. package/ui-dist/assets/{index-BRgdHUNR.js → index-CjHiMOEO.js} +1 -1
  437. package/ui-dist/assets/{index-DrL6pHSJ.js → index-CmeJQpXZ.js} +1 -1
  438. package/ui-dist/assets/index-CyuYtn7U.css +1 -0
  439. package/ui-dist/assets/{index-CKKytnOd.js → index-CzZjM8eh.js} +1 -1
  440. package/ui-dist/assets/{index-Dceamza_.js → index-D-6T0Aft.js} +1 -1
  441. package/ui-dist/assets/{index-CjDqB1SX.js → index-DG_7V1pG.js} +1 -1
  442. package/ui-dist/assets/index-DIKcgxCt.js +676 -0
  443. package/ui-dist/assets/{index-BKVeJ3Jh.js → index-DiUerHmi.js} +1 -1
  444. package/ui-dist/assets/{index-C-nKjFZh.js → index-NZ7v5Fc2.js} +1 -1
  445. package/ui-dist/assets/{index-CvPPuNs1.js → index-Py70EvBg.js} +1 -1
  446. package/ui-dist/assets/{index-LHkZdu0h.js → index-R3aYn0qM.js} +1 -1
  447. package/ui-dist/assets/{index-BT8b79Bd.js → index-YXpm7gW-.js} +1 -1
  448. package/ui-dist/assets/{index-CemenVOf.js → index-n4q3gzki.js} +1 -1
  449. package/ui-dist/assets/{index-D3ODiUup.js → index-vlZ3GoYY.js} +1 -1
  450. package/ui-dist/assets/{infoDiagram-FWYZ7A6U-C7_90qGq.js → infoDiagram-FWYZ7A6U-jdi5ciVg.js} +1 -1
  451. package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-T-nPPdTt.js → ishikawaDiagram-FXEZZL3T-CMz5VvYp.js} +1 -1
  452. package/ui-dist/assets/{journeyDiagram-5HDEW3XC-C3hqQN0R.js → journeyDiagram-5HDEW3XC-DK6dk2R-.js} +1 -1
  453. package/ui-dist/assets/{kanban-definition-HUTT4EX6-CPoD9DUm.js → kanban-definition-HUTT4EX6-DX5cZL-D.js} +1 -1
  454. package/ui-dist/assets/{linear-D-S8yr3Z.js → linear-CI96ABKp.js} +1 -1
  455. package/ui-dist/assets/{mermaid.core-DhvH8shK.js → mermaid.core-DnsEVfbd.js} +4 -4
  456. package/ui-dist/assets/{mindmap-definition-LN4V7U3C-CxCIKrKo.js → mindmap-definition-LN4V7U3C-BdDCY7hf.js} +1 -1
  457. package/ui-dist/assets/{pegDiagram-2B236MQR-D4G-PC6N.js → pegDiagram-2B236MQR-DuY4TF-f.js} +1 -1
  458. package/ui-dist/assets/{pieDiagram-ENE6RG2P-N4X8UvqY.js → pieDiagram-ENE6RG2P-bgFw7dm3.js} +1 -1
  459. package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-CZohoDln.js → quadrantDiagram-ABIIQ3AL-BCZVWyWS.js} +1 -1
  460. package/ui-dist/assets/{railroadDiagram-RFXS5EU6-fMGQVhwF.js → railroadDiagram-RFXS5EU6-D9V5_Cgc.js} +1 -1
  461. package/ui-dist/assets/{requirementDiagram-TGXJPOKE-CK0IuUmk.js → requirementDiagram-TGXJPOKE-CItsya2r.js} +1 -1
  462. package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-pSfb3CqG.js → sankeyDiagram-HTMAVEWB-Cz9IHsZO.js} +1 -1
  463. package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-CbhkqIeq.js → sequenceDiagram-DBY2YBRQ-hMSqTiwK.js} +1 -1
  464. package/ui-dist/assets/{sizeCapture-X5ZJPWSS-B6vqqPx-.js → sizeCapture-X5ZJPWSS-0g9M5wMf.js} +1 -1
  465. package/ui-dist/assets/{stateDiagram-2N3HPSRC-DIJf9h5C.js → stateDiagram-2N3HPSRC-F8_YhgWl.js} +1 -1
  466. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-fZImUBtq.js +1 -0
  467. package/ui-dist/assets/{swimlanes-5IMT3BWC-DIX_LV8O.js → swimlanes-5IMT3BWC-CCZqPbpE.js} +2 -2
  468. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-9C1UT51R.js +8 -0
  469. package/ui-dist/assets/{timeline-definition-FHXFAJF6-CD-Pxb_g.js → timeline-definition-FHXFAJF6-BeUIr18x.js} +1 -1
  470. package/ui-dist/assets/{vennDiagram-L72KCM5P-BAZsWL0R.js → vennDiagram-L72KCM5P-D3d5h_G4.js} +1 -1
  471. package/ui-dist/assets/{wardleyDiagram-EHGQE667-CnNyfwX5.js → wardleyDiagram-EHGQE667-Bzt-As9A.js} +1 -1
  472. package/ui-dist/assets/{xychartDiagram-FW5EYKEG-j9YgsD3Y.js → xychartDiagram-FW5EYKEG-C2mly0xf.js} +1 -1
  473. package/ui-dist/fonts/InterVariable-Italic.woff2 +0 -0
  474. package/ui-dist/fonts/InterVariable.woff2 +0 -0
  475. package/ui-dist/fonts/NOTICE.md +17 -0
  476. package/ui-dist/index.html +2 -2
  477. package/ui-dist/locales/en/common.json +1142 -5
  478. package/ui-dist/locales/zh-CN/common.json +1140 -3
  479. package/ui-dist/assets/channel-CsiI2LYw.js +0 -1
  480. package/ui-dist/assets/classDiagram-OUVF2IWQ-CBn1Jqo8.js +0 -1
  481. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-CBn1Jqo8.js +0 -1
  482. package/ui-dist/assets/index-BsL8K1vL.css +0 -1
  483. package/ui-dist/assets/index-D__fTsb2.js +0 -643
  484. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-DpwLD7YL.js +0 -1
  485. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-Cklauutg.js +0 -8
@@ -0,0 +1,92 @@
1
+ /**
2
+ * PAP-13775: throttle no-information issue re-wakes.
3
+ *
4
+ * After a process death (or any stall), external drivers — assignment pollers,
5
+ * stranded-issue reconcilers, on-demand invokes — can re-wake the same agent
6
+ * for the same issue every few seconds for as long as the issue stays
7
+ * `in_progress`. When each of those runs ends without changing any
8
+ * issue-visible state, every wake pays a full adapter session for zero new
9
+ * information (the Phase 4 interruption-recovery smoke paid 25 sessions and
10
+ * 2.4x cost for one recovery this way).
11
+ *
12
+ * This module decides when such a wake should be skipped: once an issue has
13
+ * accumulated a streak of consecutive succeeded-but-no-issue-progress runs by
14
+ * the same agent, further event-free wakes are held back for an escalating
15
+ * cooldown anchored to the last run's finish time. Any genuinely new input —
16
+ * a comment wake, fresh issue activity, an explicit resume, forceFreshSession,
17
+ * or an event-carrying wake reason — bypasses the throttle entirely.
18
+ *
19
+ * Server-side recovery retries (process-loss retries, missing-comment
20
+ * follow-ups) insert their runs directly and never pass through this gate, so
21
+ * crash recovery stays immediate; only repeated no-op re-invocations slow
22
+ * down.
23
+ */
24
+ /** Consecutive no-progress runs required before the cooldown engages. */
25
+ export declare const ISSUE_REWAKE_NO_PROGRESS_THRESHOLD = 2;
26
+ /** Cooldown after the threshold streak; doubles per additional no-progress run. */
27
+ export declare const ISSUE_REWAKE_BASE_COOLDOWN_MS = 120000;
28
+ /** Upper bound for the escalating cooldown. */
29
+ export declare const ISSUE_REWAKE_MAX_COOLDOWN_MS: number;
30
+ /** Only runs newer than this feed the streak; older history is ignored. */
31
+ export declare const ISSUE_REWAKE_LOOKBACK_MS: number;
32
+ /** How many recent terminal runs to sample when computing the streak. */
33
+ export declare const ISSUE_REWAKE_RUN_SAMPLE_LIMIT = 8;
34
+ /**
35
+ * Wake reasons that assert issue state rather than deliver a new event.
36
+ * These (plus reason-less on-demand invokes) are the only wakes the throttle
37
+ * applies to; every event-shaped reason (comments, mentions, blockers
38
+ * resolved, interactions, approvals, monitors, reviews, …) passes through.
39
+ */
40
+ export declare const THROTTLED_ISSUE_REWAKE_REASONS: ReadonlySet<string>;
41
+ /**
42
+ * Activity actions that count as issue-visible progress when attributed to a
43
+ * run. Deliberately narrower than run-liveness "concrete action evidence":
44
+ * tool calls inside the workspace do not move the issue, so they do not reset
45
+ * the streak — a run must leave a comment, mutation, document, work product,
46
+ * interaction, or scheduled continuation behind.
47
+ */
48
+ export declare const ISSUE_PROGRESS_ACTIVITY_ACTIONS: string[];
49
+ /**
50
+ * Activity on the issue that counts as new external input since the last run
51
+ * finished — anything a waiting agent should be woken for, including board
52
+ * responses to interactions.
53
+ */
54
+ export declare const ISSUE_NEW_INPUT_ACTIVITY_ACTIONS: string[];
55
+ export interface IssueRewakeCandidateInput {
56
+ reason: string | null;
57
+ wakeCommentId: string | null;
58
+ forceFreshSession: boolean;
59
+ hasExplicitResume: boolean;
60
+ }
61
+ /**
62
+ * Whether a wake is even a candidate for throttling. Wakes that carry new
63
+ * information or an explicit operator escalation always pass.
64
+ */
65
+ export declare function isThrottleCandidateIssueRewake(input: IssueRewakeCandidateInput): boolean;
66
+ export interface RecentIssueRunSample {
67
+ id: string;
68
+ status: string;
69
+ finishedAt: Date | null;
70
+ }
71
+ export interface IssueRewakeThrottleInput {
72
+ now: Date;
73
+ /** Terminal runs for the same (agent, issue), newest finish first. */
74
+ recentTerminalRuns: RecentIssueRunSample[];
75
+ /** Runs among the sample that produced issue-visible progress. */
76
+ runIdsWithIssueProgress: ReadonlySet<string>;
77
+ /** New issue input landed after the newest run finished. */
78
+ hasNewIssueInputSinceLastRun: boolean;
79
+ }
80
+ export type IssueRewakeThrottleDecision = {
81
+ blocked: false;
82
+ noProgressStreak: number;
83
+ } | {
84
+ blocked: true;
85
+ noProgressStreak: number;
86
+ cooldownMs: number;
87
+ lastRunFinishedAt: Date;
88
+ nextAllowedAt: Date;
89
+ };
90
+ export declare function computeIssueRewakeCooldownMs(noProgressStreak: number): number;
91
+ export declare function evaluateIssueRewakeThrottle(input: IssueRewakeThrottleInput): IssueRewakeThrottleDecision;
92
+ //# sourceMappingURL=issue-rewake-throttle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-rewake-throttle.d.ts","sourceRoot":"","sources":["../../src/services/issue-rewake-throttle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,yEAAyE;AACzE,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,mFAAmF;AACnF,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD,+CAA+C;AAC/C,eAAO,MAAM,4BAA4B,QAAc,CAAC;AAExD,2EAA2E;AAC3E,eAAO,MAAM,wBAAwB,QAAkB,CAAC;AAExD,yEAAyE;AACzE,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,EAAE,WAAW,CAAC,MAAM,CAK7D,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,EAuBnD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,EAAE,MAAM,EAMpD,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAMxF;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,GAAG,EAAE,IAAI,CAAC;IACV,sEAAsE;IACtE,kBAAkB,EAAE,oBAAoB,EAAE,CAAC;IAC3C,kEAAkE;IAClE,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,4DAA4D;IAC5D,4BAA4B,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,MAAM,2BAA2B,GACnC;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAC5C;IACE,OAAO,EAAE,IAAI,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,IAAI,CAAC;IACxB,aAAa,EAAE,IAAI,CAAC;CACrB,CAAC;AAEN,wBAAgB,4BAA4B,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAK7E;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,wBAAwB,GAAG,2BAA2B,CA2BxG"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * PAP-13775: throttle no-information issue re-wakes.
3
+ *
4
+ * After a process death (or any stall), external drivers — assignment pollers,
5
+ * stranded-issue reconcilers, on-demand invokes — can re-wake the same agent
6
+ * for the same issue every few seconds for as long as the issue stays
7
+ * `in_progress`. When each of those runs ends without changing any
8
+ * issue-visible state, every wake pays a full adapter session for zero new
9
+ * information (the Phase 4 interruption-recovery smoke paid 25 sessions and
10
+ * 2.4x cost for one recovery this way).
11
+ *
12
+ * This module decides when such a wake should be skipped: once an issue has
13
+ * accumulated a streak of consecutive succeeded-but-no-issue-progress runs by
14
+ * the same agent, further event-free wakes are held back for an escalating
15
+ * cooldown anchored to the last run's finish time. Any genuinely new input —
16
+ * a comment wake, fresh issue activity, an explicit resume, forceFreshSession,
17
+ * or an event-carrying wake reason — bypasses the throttle entirely.
18
+ *
19
+ * Server-side recovery retries (process-loss retries, missing-comment
20
+ * follow-ups) insert their runs directly and never pass through this gate, so
21
+ * crash recovery stays immediate; only repeated no-op re-invocations slow
22
+ * down.
23
+ */
24
+ /** Consecutive no-progress runs required before the cooldown engages. */
25
+ export const ISSUE_REWAKE_NO_PROGRESS_THRESHOLD = 2;
26
+ /** Cooldown after the threshold streak; doubles per additional no-progress run. */
27
+ export const ISSUE_REWAKE_BASE_COOLDOWN_MS = 120_000;
28
+ /** Upper bound for the escalating cooldown. */
29
+ export const ISSUE_REWAKE_MAX_COOLDOWN_MS = 30 * 60_000;
30
+ /** Only runs newer than this feed the streak; older history is ignored. */
31
+ export const ISSUE_REWAKE_LOOKBACK_MS = 6 * 60 * 60_000;
32
+ /** How many recent terminal runs to sample when computing the streak. */
33
+ export const ISSUE_REWAKE_RUN_SAMPLE_LIMIT = 8;
34
+ /**
35
+ * Wake reasons that assert issue state rather than deliver a new event.
36
+ * These (plus reason-less on-demand invokes) are the only wakes the throttle
37
+ * applies to; every event-shaped reason (comments, mentions, blockers
38
+ * resolved, interactions, approvals, monitors, reviews, …) passes through.
39
+ */
40
+ export const THROTTLED_ISSUE_REWAKE_REASONS = new Set([
41
+ "issue_assigned",
42
+ "issue_continuation_needed",
43
+ "issue_assignment_recovery",
44
+ "issue_graph_liveness_backstop",
45
+ ]);
46
+ /**
47
+ * Activity actions that count as issue-visible progress when attributed to a
48
+ * run. Deliberately narrower than run-liveness "concrete action evidence":
49
+ * tool calls inside the workspace do not move the issue, so they do not reset
50
+ * the streak — a run must leave a comment, mutation, document, work product,
51
+ * interaction, or scheduled continuation behind.
52
+ */
53
+ export const ISSUE_PROGRESS_ACTIVITY_ACTIONS = [
54
+ "issue.updated",
55
+ "issue.comment_added",
56
+ "issue.created",
57
+ "issue.child_created",
58
+ "issue.assigned",
59
+ "issue.released",
60
+ "issue.blockers_updated",
61
+ "issue.document_upserted",
62
+ "issue.document_updated",
63
+ "issue.document_deleted",
64
+ "issue.document_restored",
65
+ "issue.document_annotation_comment_added",
66
+ "issue.document_annotation_thread_created",
67
+ "issue.document_annotation_thread_resolved",
68
+ "issue.work_product_created",
69
+ "issue.work_product_updated",
70
+ "issue.work_product_deleted",
71
+ "issue.attachment_added",
72
+ "issue.attachment_removed",
73
+ "issue.thread_interaction_created",
74
+ "issue.monitor_scheduled",
75
+ "issue.approval_linked",
76
+ ];
77
+ /**
78
+ * Activity on the issue that counts as new external input since the last run
79
+ * finished — anything a waiting agent should be woken for, including board
80
+ * responses to interactions.
81
+ */
82
+ export const ISSUE_NEW_INPUT_ACTIVITY_ACTIONS = [
83
+ ...ISSUE_PROGRESS_ACTIVITY_ACTIONS,
84
+ "issue.thread_interaction_accepted",
85
+ "issue.thread_interaction_answered",
86
+ "issue.thread_interaction_item_verdicts_submitted",
87
+ "issue.blockers_resolved_wake_emitted",
88
+ ];
89
+ /**
90
+ * Whether a wake is even a candidate for throttling. Wakes that carry new
91
+ * information or an explicit operator escalation always pass.
92
+ */
93
+ export function isThrottleCandidateIssueRewake(input) {
94
+ if (input.forceFreshSession)
95
+ return false;
96
+ if (input.wakeCommentId)
97
+ return false;
98
+ if (input.hasExplicitResume)
99
+ return false;
100
+ if (input.reason === null)
101
+ return true;
102
+ return THROTTLED_ISSUE_REWAKE_REASONS.has(input.reason);
103
+ }
104
+ export function computeIssueRewakeCooldownMs(noProgressStreak) {
105
+ const doublings = Math.max(0, noProgressStreak - ISSUE_REWAKE_NO_PROGRESS_THRESHOLD);
106
+ // Guard the exponent so an absurd streak can't overflow into Infinity.
107
+ const factor = 2 ** Math.min(doublings, 16);
108
+ return Math.min(ISSUE_REWAKE_BASE_COOLDOWN_MS * factor, ISSUE_REWAKE_MAX_COOLDOWN_MS);
109
+ }
110
+ export function evaluateIssueRewakeThrottle(input) {
111
+ const runs = input.recentTerminalRuns;
112
+ if (runs.length === 0)
113
+ return { blocked: false, noProgressStreak: 0 };
114
+ if (input.hasNewIssueInputSinceLastRun)
115
+ return { blocked: false, noProgressStreak: 0 };
116
+ let noProgressStreak = 0;
117
+ for (const run of runs) {
118
+ // A failed/cancelled/interrupted run breaks the streak: its follow-up is
119
+ // recovery, not a redundant re-poll, and must not be delayed.
120
+ if (run.status !== "succeeded" || !run.finishedAt)
121
+ break;
122
+ if (input.runIdsWithIssueProgress.has(run.id))
123
+ break;
124
+ noProgressStreak += 1;
125
+ }
126
+ if (noProgressStreak < ISSUE_REWAKE_NO_PROGRESS_THRESHOLD) {
127
+ return { blocked: false, noProgressStreak };
128
+ }
129
+ const lastRunFinishedAt = runs[0]?.finishedAt;
130
+ if (!lastRunFinishedAt)
131
+ return { blocked: false, noProgressStreak };
132
+ const cooldownMs = computeIssueRewakeCooldownMs(noProgressStreak);
133
+ const nextAllowedAt = new Date(lastRunFinishedAt.getTime() + cooldownMs);
134
+ if (input.now.getTime() < nextAllowedAt.getTime()) {
135
+ return { blocked: true, noProgressStreak, cooldownMs, lastRunFinishedAt, nextAllowedAt };
136
+ }
137
+ return { blocked: false, noProgressStreak };
138
+ }
139
+ //# sourceMappingURL=issue-rewake-throttle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-rewake-throttle.js","sourceRoot":"","sources":["../../src/services/issue-rewake-throttle.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { Db } from "@penclipai/db";
2
2
  import { issueThreadInteractions } from "@penclipai/db";
3
- import type { AcceptIssueThreadInteraction, CancelIssueThreadInteraction, CreateIssueThreadInteraction, IssueThreadInteraction, RejectIssueThreadInteraction, RespondIssueThreadInteraction } from "@penclipai/shared";
3
+ import type { AcceptIssueThreadInteraction, CancelIssueThreadInteraction, CreateIssueThreadInteraction, IssueThreadInteraction, RejectIssueThreadInteraction, RespondIssueThreadInteraction, SubmitIssueThreadInteractionVerdicts } from "@penclipai/shared";
4
4
  type InteractionActor = {
5
5
  agentId?: string | null;
6
6
  userId?: string | null;
@@ -43,6 +43,13 @@ export declare function issueThreadInteractionService(db: Db): {
43
43
  id: string;
44
44
  companyId: string;
45
45
  }, interactionId: string, input: RejectIssueThreadInteraction, actor: InteractionActor) => Promise<IssueThreadInteraction>;
46
+ submitItemVerdicts: (issue: {
47
+ id: string;
48
+ companyId: string;
49
+ }, interactionId: string, input: SubmitIssueThreadInteractionVerdicts, actor: InteractionActor) => Promise<{
50
+ interaction: IssueThreadInteraction;
51
+ newlyResolvedItemIds: string[];
52
+ }>;
46
53
  rejectSuggestedTasks: (issue: {
47
54
  id: string;
48
55
  companyId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"issue-thread-interactions.d.ts","sourceRoot":"","sources":["../../src/services/issue-thread-interactions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"issue-thread-interactions.d.ts","sourceRoot":"","sources":["../../src/services/issue-thread-interactions.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { isDeepStrictEqual } from "node:util";
2
2
  import { and, asc, eq, inArray, isNotNull } from "drizzle-orm";
3
3
  import { agents, documents, heartbeatRuns, issueComments, issueDocuments, issueThreadInteractions, issues, } from "@penclipai/db";
4
4
  import { trackInteractionResolved } from "@penclipai/shared/telemetry";
5
- import { acceptIssueThreadInteractionSchema, askUserQuestionsPayloadSchema, askUserQuestionsResultSchema, cancelIssueThreadInteractionSchema, createIssueThreadInteractionSchema, rejectIssueThreadInteractionSchema, requestCheckboxConfirmationPayloadSchema, requestCheckboxConfirmationResultSchema, requestConfirmationPayloadSchema, requestConfirmationResultSchema, suggestTasksPayloadSchema, suggestTasksResultSchema, } from "@penclipai/shared";
5
+ import { acceptIssueThreadInteractionSchema, askUserQuestionsPayloadSchema, askUserQuestionsResultSchema, cancelIssueThreadInteractionSchema, createIssueThreadInteractionSchema, rejectIssueThreadInteractionSchema, requestCheckboxConfirmationPayloadSchema, requestCheckboxConfirmationResultSchema, requestConfirmationPayloadSchema, requestConfirmationResultSchema, requestItemVerdictsPayloadSchema, requestItemVerdictsResultSchema, suggestTasksPayloadSchema, suggestTasksResultSchema, submitIssueThreadInteractionVerdictsSchema, } from "@penclipai/shared";
6
6
  import { conflict, notFound, unprocessable } from "../errors.js";
7
7
  import { isUniqueViolation } from "./db-errors.js";
8
8
  import { getTelemetryClient } from "../telemetry.js";
@@ -12,13 +12,20 @@ const REQUEST_CONFIRMATION_INTERACTION_KINDS = [
12
12
  "request_confirmation",
13
13
  "request_checkbox_confirmation",
14
14
  ];
15
- const USER_COMMENT_SUPERSEDABLE_INTERACTION_KINDS = [
15
+ const TARGET_BOUND_INTERACTION_KINDS = [
16
16
  ...REQUEST_CONFIRMATION_INTERACTION_KINDS,
17
+ "request_item_verdicts",
18
+ ];
19
+ const USER_COMMENT_SUPERSEDABLE_INTERACTION_KINDS = [
20
+ ...TARGET_BOUND_INTERACTION_KINDS,
17
21
  "ask_user_questions",
18
22
  ];
19
23
  function isRequestConfirmationLikeKind(kind) {
20
24
  return REQUEST_CONFIRMATION_INTERACTION_KINDS.includes(kind);
21
25
  }
26
+ function isTargetBoundInteractionKind(kind) {
27
+ return TARGET_BOUND_INTERACTION_KINDS.includes(kind);
28
+ }
22
29
  function isUserCommentSupersedableKind(kind) {
23
30
  return USER_COMMENT_SUPERSEDABLE_INTERACTION_KINDS.includes(kind);
24
31
  }
@@ -73,6 +80,13 @@ function hydrateInteraction(row) {
73
80
  payload: requestCheckboxConfirmationPayloadSchema.parse(row.payload),
74
81
  result: row.result ? requestCheckboxConfirmationResultSchema.parse(row.result) : null,
75
82
  };
83
+ case "request_item_verdicts":
84
+ return {
85
+ ...base,
86
+ kind: "request_item_verdicts",
87
+ payload: requestItemVerdictsPayloadSchema.parse(row.payload),
88
+ result: row.result ? requestItemVerdictsResultSchema.parse(row.result) : null,
89
+ };
76
90
  default:
77
91
  throw unprocessable(`Unknown interaction kind: ${row.kind}`);
78
92
  }
@@ -130,6 +144,14 @@ function normalizeCreateInteractionInput(input) {
130
144
  supersedeOnUserComment: input.payload.supersedeOnUserComment ?? true,
131
145
  },
132
146
  };
147
+ case "request_item_verdicts":
148
+ return {
149
+ ...input,
150
+ payload: {
151
+ ...input.payload,
152
+ supersedeOnUserComment: input.payload.supersedeOnUserComment ?? true,
153
+ },
154
+ };
133
155
  default:
134
156
  return input;
135
157
  }
@@ -144,12 +166,39 @@ function buildSupersededByCommentResult(row, commentId) {
144
166
  summaryMarkdown: null,
145
167
  };
146
168
  }
169
+ if (row.kind === "request_item_verdicts") {
170
+ const interaction = hydrateInteraction(row);
171
+ return {
172
+ version: 1,
173
+ outcome: "superseded_by_comment",
174
+ complete: false,
175
+ items: interaction.result?.items ?? [],
176
+ commentId,
177
+ };
178
+ }
147
179
  return {
148
180
  version: 1,
149
181
  outcome: "superseded_by_comment",
150
182
  commentId,
151
183
  };
152
184
  }
185
+ function buildStaleTargetResult(row, staleTarget) {
186
+ if (row.kind === "request_item_verdicts") {
187
+ const interaction = hydrateInteraction(row);
188
+ return {
189
+ version: 1,
190
+ outcome: "stale_target",
191
+ complete: false,
192
+ items: interaction.result?.items ?? [],
193
+ staleTarget,
194
+ };
195
+ }
196
+ return {
197
+ version: 1,
198
+ outcome: "stale_target",
199
+ staleTarget,
200
+ };
201
+ }
153
202
  function resolveActorKind(interaction) {
154
203
  if (interaction.resolvedByAgentId)
155
204
  return "agent";
@@ -165,10 +214,14 @@ function resolveCreatorKind(interaction) {
165
214
  return undefined;
166
215
  }
167
216
  function deriveTargetType(interaction) {
168
- if (interaction.kind !== "request_confirmation" && interaction.kind !== "request_checkbox_confirmation") {
169
- return "none";
217
+ switch (interaction.kind) {
218
+ case "request_confirmation":
219
+ case "request_checkbox_confirmation":
220
+ case "request_item_verdicts":
221
+ return interaction.payload.target?.type ?? "none";
222
+ default:
223
+ return "none";
170
224
  }
171
- return interaction.payload.target?.type ?? "none";
172
225
  }
173
226
  function deriveResolutionReason(interaction) {
174
227
  switch (interaction.status) {
@@ -185,8 +238,17 @@ function deriveResolutionReason(interaction) {
185
238
  if (interaction.kind === "request_confirmation" || interaction.kind === "request_checkbox_confirmation") {
186
239
  return interaction.result?.outcome ?? "expired";
187
240
  }
241
+ if (interaction.kind === "request_item_verdicts") {
242
+ return interaction.result?.outcome ?? "expired";
243
+ }
188
244
  return "expired";
189
245
  }
246
+ case "answered": {
247
+ if (interaction.kind === "request_item_verdicts") {
248
+ return interaction.result?.outcome ?? "answered";
249
+ }
250
+ return "answered";
251
+ }
190
252
  default:
191
253
  return undefined;
192
254
  }
@@ -213,6 +275,11 @@ function buildInteractionResolvedCounts(interaction, args) {
213
275
  questionCount: nonNegativeInteger(interaction.payload.questions.length),
214
276
  answeredQuestionCount: nonNegativeInteger(interaction.result?.answers?.length ?? 0),
215
277
  };
278
+ case "request_item_verdicts":
279
+ return {
280
+ itemCount: nonNegativeInteger(interaction.payload.items.length),
281
+ resolvedItemCount: nonNegativeInteger(interaction.result?.items?.length ?? 0),
282
+ };
216
283
  default:
217
284
  return {};
218
285
  }
@@ -366,6 +433,56 @@ function resolveSelectedCheckboxConfirmationOptions(args) {
366
433
  .filter((option) => selectedOptionIdSet.has(option.id))
367
434
  .map((option) => option.id);
368
435
  }
436
+ function resolveRequestItemVerdictSubmissions(args) {
437
+ if (!args.actor.userId) {
438
+ throw unprocessable("request_item_verdicts submissions require a user actor");
439
+ }
440
+ const existingItems = args.interaction.result?.items ?? [];
441
+ const existingById = new Map(existingItems.map((item) => [item.id, item]));
442
+ const payloadItemIds = new Set(args.interaction.payload.items.map((item) => item.id));
443
+ const enabledVerdicts = new Set(args.interaction.payload.verdicts ?? ["approve", "reject"]);
444
+ const requireReasonOn = new Set(args.interaction.payload.requireReasonOn ?? ["reject"]);
445
+ const newlyResolvedById = new Map();
446
+ const newlyResolvedItemIds = [];
447
+ for (const submitted of args.input.verdicts) {
448
+ if (!payloadItemIds.has(submitted.id)) {
449
+ throw unprocessable(`Unknown item verdict id: ${submitted.id}`);
450
+ }
451
+ if (existingById.has(submitted.id)) {
452
+ continue;
453
+ }
454
+ if (!enabledVerdicts.has(submitted.verdict)) {
455
+ throw unprocessable(`Verdict ${submitted.verdict} is not enabled for this item verdict request`);
456
+ }
457
+ const reason = submitted.reason?.trim() ?? "";
458
+ if (requireReasonOn.has(submitted.verdict) && reason.length === 0) {
459
+ throw unprocessable(`A reason is required when verdict is ${submitted.verdict}`);
460
+ }
461
+ if (newlyResolvedById.has(submitted.id)) {
462
+ continue;
463
+ }
464
+ newlyResolvedById.set(submitted.id, {
465
+ id: submitted.id,
466
+ verdict: submitted.verdict,
467
+ ...(reason ? { reason } : {}),
468
+ resolvedByUserId: args.actor.userId,
469
+ resolvedAt: args.now,
470
+ });
471
+ newlyResolvedItemIds.push(submitted.id);
472
+ }
473
+ const nextById = new Map(existingItems.map((item) => [item.id, item]));
474
+ for (const [id, item] of newlyResolvedById) {
475
+ nextById.set(id, item);
476
+ }
477
+ const items = args.interaction.payload.items
478
+ .map((item) => nextById.get(item.id))
479
+ .filter((item) => Boolean(item));
480
+ return {
481
+ items,
482
+ complete: items.length === args.interaction.payload.items.length,
483
+ newlyResolvedItemIds,
484
+ };
485
+ }
369
486
  function normalizeQuestionAnswers(args) {
370
487
  const questionById = new Map(args.questions.map((question) => [question.id, question]));
371
488
  const answerByQuestionId = new Map();
@@ -469,7 +586,7 @@ async function assertRequestConfirmationTargetIsCurrent(db, args) {
469
586
  }
470
587
  }
471
588
  async function expireStaleRequestConfirmationTarget(db, args) {
472
- if (!isRequestConfirmationLikeKind(args.row.kind) || args.row.status !== "pending")
589
+ if (!isTargetBoundInteractionKind(args.row.kind) || args.row.status !== "pending")
473
590
  return null;
474
591
  const interaction = hydrateInteraction(args.row);
475
592
  const target = interaction.payload.target ?? null;
@@ -503,9 +620,7 @@ async function expireStaleRequestConfirmationTarget(db, args) {
503
620
  }
504
621
  : interaction.payload,
505
622
  result: {
506
- version: 1,
507
- outcome: "stale_target",
508
- staleTarget: target,
623
+ ...buildStaleTargetResult(args.row, target),
509
624
  },
510
625
  resolvedByAgentId: args.actor.agentId ?? null,
511
626
  resolvedByUserId: args.actor.userId ?? null,
@@ -743,7 +858,9 @@ export function issueThreadInteractionService(db) {
743
858
  throw unprocessable("sourceRunId must belong to the same company");
744
859
  }
745
860
  }
746
- if (data.kind === "request_confirmation" || data.kind === "request_checkbox_confirmation") {
861
+ if (data.kind === "request_confirmation"
862
+ || data.kind === "request_checkbox_confirmation"
863
+ || data.kind === "request_item_verdicts") {
747
864
  await assertRequestConfirmationTargetIsCurrent(db, {
748
865
  companyId: issue.companyId,
749
866
  issueId: issue.id,
@@ -982,6 +1099,90 @@ export function issueThreadInteractionService(db) {
982
1099
  throw unprocessable(`Interactions of kind ${current.kind} cannot be rejected`);
983
1100
  }
984
1101
  },
1102
+ submitItemVerdicts: async (issue, interactionId, input, actor) => {
1103
+ const data = submitIssueThreadInteractionVerdictsSchema.parse(input);
1104
+ const submission = await db.transaction(async (tx) => {
1105
+ const current = await tx
1106
+ .select()
1107
+ .from(issueThreadInteractions)
1108
+ .where(eq(issueThreadInteractions.id, interactionId))
1109
+ .for("update")
1110
+ .then((rows) => rows[0] ?? null);
1111
+ if (!current)
1112
+ throw notFound("Interaction not found");
1113
+ if (current.companyId !== issue.companyId || current.issueId !== issue.id) {
1114
+ throw notFound("Interaction not found");
1115
+ }
1116
+ if (current.kind !== "request_item_verdicts") {
1117
+ throw unprocessable("Only request_item_verdicts interactions can receive item verdicts");
1118
+ }
1119
+ const interaction = hydrateInteraction(current);
1120
+ if (current.status !== "pending") {
1121
+ if (current.status === "answered") {
1122
+ const resolvedIds = new Set(interaction.result?.items.map((item) => item.id) ?? []);
1123
+ const payloadIds = new Set(interaction.payload.items.map((item) => item.id));
1124
+ for (const submitted of data.verdicts) {
1125
+ if (!payloadIds.has(submitted.id)) {
1126
+ throw unprocessable(`Unknown item verdict id: ${submitted.id}`);
1127
+ }
1128
+ if (!resolvedIds.has(submitted.id)) {
1129
+ throw conflict("Interaction has already been resolved");
1130
+ }
1131
+ }
1132
+ return { interaction, newlyResolvedItemIds: [], resolved: false };
1133
+ }
1134
+ throw conflict("Interaction has already been resolved");
1135
+ }
1136
+ const expired = await expireStaleRequestConfirmationTarget(tx, {
1137
+ row: current,
1138
+ actor,
1139
+ });
1140
+ if (expired) {
1141
+ return { interaction: expired, newlyResolvedItemIds: [], resolved: false };
1142
+ }
1143
+ const now = new Date();
1144
+ const { items, complete, newlyResolvedItemIds } = resolveRequestItemVerdictSubmissions({
1145
+ interaction,
1146
+ input: data,
1147
+ actor,
1148
+ now,
1149
+ });
1150
+ if (newlyResolvedItemIds.length === 0) {
1151
+ return { interaction, newlyResolvedItemIds: [], resolved: false };
1152
+ }
1153
+ const result = {
1154
+ version: 1,
1155
+ outcome: "resolved",
1156
+ complete,
1157
+ items,
1158
+ };
1159
+ const [updated] = await tx
1160
+ .update(issueThreadInteractions)
1161
+ .set({
1162
+ status: complete ? "answered" : "pending",
1163
+ result,
1164
+ resolvedByAgentId: complete ? actor.agentId ?? null : null,
1165
+ resolvedByUserId: complete ? actor.userId ?? null : null,
1166
+ resolvedAt: complete ? now : null,
1167
+ updatedAt: now,
1168
+ })
1169
+ .where(and(eq(issueThreadInteractions.id, interactionId), eq(issueThreadInteractions.status, "pending")))
1170
+ .returning();
1171
+ if (!updated) {
1172
+ throw conflict("Interaction has already been resolved");
1173
+ }
1174
+ await touchIssue(tx, issue.id);
1175
+ return {
1176
+ interaction: hydrateInteraction(updated),
1177
+ newlyResolvedItemIds,
1178
+ resolved: complete,
1179
+ };
1180
+ });
1181
+ if (submission.resolved) {
1182
+ await emitInteractionResolvedTelemetry(db, submission.interaction);
1183
+ }
1184
+ return submission;
1185
+ },
985
1186
  rejectSuggestedTasks: async (issue, interactionId, input, actor, current) => {
986
1187
  if (current.companyId !== issue.companyId || current.issueId !== issue.id) {
987
1188
  throw notFound("Interaction not found");
@@ -1109,6 +1310,8 @@ export function issueThreadInteractionService(db) {
1109
1310
  const confirmationRowIds = commentRows
1110
1311
  .filter((row) => isRequestConfirmationLikeKind(row.kind))
1111
1312
  .map((row) => row.id);
1313
+ const itemVerdictRows = commentRows
1314
+ .filter((row) => row.kind === "request_item_verdicts");
1112
1315
  if (questionRowIds.length > 0) {
1113
1316
  const sampleQuestionRow = commentRows.find((row) => row.kind === "ask_user_questions");
1114
1317
  if (!sampleQuestionRow)
@@ -1145,6 +1348,22 @@ export function issueThreadInteractionService(db) {
1145
1348
  .returning();
1146
1349
  expired.push(...updatedRows.map(hydrateInteraction));
1147
1350
  }
1351
+ for (const row of itemVerdictRows) {
1352
+ const [updated] = await db
1353
+ .update(issueThreadInteractions)
1354
+ .set({
1355
+ status: "expired",
1356
+ result: buildSupersededByCommentResult(row, comment.id),
1357
+ resolvedByAgentId: null,
1358
+ resolvedByUserId: comment.authorUserId,
1359
+ resolvedAt: now,
1360
+ updatedAt: now,
1361
+ })
1362
+ .where(and(eq(issueThreadInteractions.id, row.id), eq(issueThreadInteractions.status, "pending")))
1363
+ .returning();
1364
+ if (updated)
1365
+ expired.push(hydrateInteraction(updated));
1366
+ }
1148
1367
  }
1149
1368
  if (expired.length > 0) {
1150
1369
  await touchIssue(db, issue.id);
@@ -1156,7 +1375,7 @@ export function issueThreadInteractionService(db) {
1156
1375
  const rows = await db
1157
1376
  .select()
1158
1377
  .from(issueThreadInteractions)
1159
- .where(and(eq(issueThreadInteractions.companyId, issue.companyId), eq(issueThreadInteractions.issueId, issue.id), inArray(issueThreadInteractions.kind, [...REQUEST_CONFIRMATION_INTERACTION_KINDS]), eq(issueThreadInteractions.status, "pending")));
1378
+ .where(and(eq(issueThreadInteractions.companyId, issue.companyId), eq(issueThreadInteractions.issueId, issue.id), inArray(issueThreadInteractions.kind, [...TARGET_BOUND_INTERACTION_KINDS]), eq(issueThreadInteractions.status, "pending")));
1160
1379
  const staleRows = rows.filter((row) => {
1161
1380
  const interaction = hydrateInteraction(row);
1162
1381
  const target = interaction.payload.target;
@@ -1195,11 +1414,7 @@ export function issueThreadInteractionService(db) {
1195
1414
  target: currentTarget,
1196
1415
  }
1197
1416
  : interaction.payload,
1198
- result: {
1199
- version: 1,
1200
- outcome: "stale_target",
1201
- staleTarget: target,
1202
- },
1417
+ result: buildStaleTargetResult(row, target),
1203
1418
  resolvedByAgentId: actor.agentId ?? null,
1204
1419
  resolvedByUserId: actor.userId ?? null,
1205
1420
  resolvedAt: now,