@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
@@ -1,11 +1,11 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { createHash } from "node:crypto";
3
- import { and, asc, desc, eq, gt, inArray, isNull, like, lt, ne, notInArray, or, sql } from "drizzle-orm";
4
- import { activityLog, agentWakeupRequests, agents, authUsers, approvals, assets, companies, companyMemberships, documentRevisions, documents, goals, heartbeatRuns, executionWorkspaces, issueApprovals, issueAttachments, issueInboxArchives, issueLabels, issueWatchdogs, issuePlanDecompositions, issueRecoveryActions, issueRelations, issueComments, issueDocuments, issueReadStates, issueThreadInteractions, issues, labels, projectWorkspaces, projects, workspaceOperations, } from "@penclipai/db";
3
+ import { and, asc, desc, eq, gt, gte, inArray, isNull, like, lt, ne, notInArray, or, sql } from "drizzle-orm";
4
+ import { activityLog, agentWakeupRequests, agents, authUsers, approvals, assets, companies, companyMemberships, documentRevisions, documents, goals, heartbeatRuns, routineRuns, executionWorkspaces, issueApprovals, issueAttachments, issueInboxArchives, issueLabels, issueWatchdogs, issuePlanDecompositions, issueRecoveryActions, issueRelations, issueComments, issueDocuments, issueReadStates, issueThreadInteractions, issues, labels, projectWorkspaces, projects, workspaceOperations, } from "@penclipai/db";
5
5
  import { clampIssueRequestDepth, extractAgentMentionIds, extractProjectMentionIds, issueCommentAuthorTypeSchema, issueCommentMetadataSchema, issueCommentPresentationSchema, isUuidLike, normalizeIssueIdentifier as normalizeIssueReferenceIdentifier, } from "@penclipai/shared";
6
6
  import { conflict, HttpError, notFound, unprocessable } from "../errors.js";
7
7
  import { logger } from "../middleware/logger.js";
8
- import { defaultIssueExecutionWorkspaceSettingsForProject, gateProjectExecutionWorkspacePolicy, issueExecutionWorkspaceModeForPersistedWorkspace, parseIssueExecutionWorkspaceSettings, parseProjectExecutionWorkspacePolicy, } from "./execution-workspace-policy.js";
8
+ import { defaultIssueExecutionWorkspaceSettingsForProject, gateProjectExecutionWorkspacePolicy, issueExecutionWorkspaceModeForPersistedWorkspace, isUnrunnableWorktreeCombo, parseIssueExecutionWorkspaceSettings, parseProjectExecutionWorkspacePolicy, resolvePinnedIssueWorkspaceStrategyType, WORKSPACE_WORKTREE_REQUIRES_PROJECT_CODE, WORKSPACE_WORKTREE_REQUIRES_PROJECT_MESSAGE, WORKSPACE_WORKTREE_REQUIRES_PROJECT_REMEDIATION, } from "./execution-workspace-policy.js";
9
9
  import { mergeExecutionWorkspaceConfig } from "./execution-workspaces.js";
10
10
  import { buildInitialIssueMonitorFields, normalizeIssueExecutionPolicy } from "./issue-execution-policy.js";
11
11
  import { instanceSettingsService } from "./instance-settings.js";
@@ -19,10 +19,20 @@ import { summarizeIssueWatchdog, upsertIssueWatchdogForIssue, } from "./task-wat
19
19
  import { isVerifiedIssueTreeControlInteractionWake, issueTreeControlService, } from "./issue-tree-control.js";
20
20
  import { parseIssueGraphLivenessIncidentKey, RECOVERY_ORIGIN_KINDS, } from "./recovery/origins.js";
21
21
  import { classifyIssueGraphLiveness } from "./recovery/issue-graph-liveness.js";
22
+ import { visibleIssueCondition } from "./issue-visibility.js";
22
23
  const ALL_ISSUE_STATUSES = ["backlog", "todo", "in_progress", "in_review", "blocked", "done", "cancelled"];
23
24
  const MAX_ISSUE_COMMENT_PAGE_LIMIT = 500;
24
25
  export const ISSUE_LIST_DEFAULT_LIMIT = 500;
25
26
  export const ISSUE_LIST_MAX_LIMIT = 1000;
27
+ export const ISSUE_BLOCKER_DIAGNOSTICS_MAX_BLOCKERS = 100;
28
+ export const ISSUE_WAKE_DIAGNOSTICS_MAX_WAKE_REQUESTS = 50;
29
+ export const ISSUE_WAKE_DIAGNOSTICS_MAX_ACTIVITY_RECORDS = 50;
30
+ export const ISSUE_WAKE_DIAGNOSTICS_LOOKBACK_DAYS = 14;
31
+ export const ISSUE_SUBTREE_DIAGNOSTICS_MAX_DEPTH = 8;
32
+ export const ISSUE_SUBTREE_DIAGNOSTICS_MAX_NODES = 100;
33
+ export const ISSUE_SUBTREE_DIAGNOSTICS_MAX_BLOCKERS_PER_NODE = 20;
34
+ export const ISSUE_SUBTREE_DIAGNOSTICS_MAX_WAKE_REQUESTS_PER_NODE = 5;
35
+ export const ISSUE_SUBTREE_DIAGNOSTICS_MAX_ACTIVITY_RECORDS_PER_NODE = 5;
26
36
  const ISSUE_LIST_RELATED_QUERY_CHUNK_SIZE = 500;
27
37
  export const MAX_CHILD_ISSUES_CREATED_BY_HELPER = 25;
28
38
  const MAX_CHILD_COMPLETION_SUMMARIES = 20;
@@ -37,6 +47,22 @@ const ISSUE_COMMENT_RUN_LOG_DERIVATION_CHUNK_BYTES = 256_000;
37
47
  const ISSUE_COMMENT_RUN_LOG_DERIVATION_END_SLACK_MS = 60_000;
38
48
  const ISSUE_COMMENT_RUN_LOG_DERIVATION_MAX_PARALLEL_READS = 8;
39
49
  const DELETED_ISSUE_COMMENT_BODY = "";
50
+ const ISSUE_WAKE_DIAGNOSTICS_ACTIVITY_ACTIONS = ["issue.tree_hold_wakeup_deferred"];
51
+ function wakeRequestTargetsIssue(issueId) {
52
+ return sql `(
53
+ ${agentWakeupRequests.payload} ->> 'issueId' = ${issueId}
54
+ or ${agentWakeupRequests.payload} ->> 'taskId' = ${issueId}
55
+ or ${agentWakeupRequests.payload} -> '_paperclipWakeContext' ->> 'issueId' = ${issueId}
56
+ or ${agentWakeupRequests.payload} -> '_paperclipWakeContext' ->> 'taskId' = ${issueId}
57
+ )`;
58
+ }
59
+ function wakeDiagnosticActivityTargetsIssue(issueId) {
60
+ return sql `(
61
+ (${activityLog.entityType} = 'issue' and ${activityLog.entityId} = ${issueId})
62
+ or ${activityLog.details} ->> 'issueId' = ${issueId}
63
+ or ${activityLog.details} ->> 'rootIssueId' = ${issueId}
64
+ )`;
65
+ }
40
66
  function assertTransition(from, to) {
41
67
  if (from === to)
42
68
  return;
@@ -58,12 +84,82 @@ function applyStatusSideEffects(status, patch) {
58
84
  }
59
85
  return patch;
60
86
  }
87
+ function workspaceWorktreeRequiresProjectDetails() {
88
+ return {
89
+ code: WORKSPACE_WORKTREE_REQUIRES_PROJECT_CODE,
90
+ remediation: WORKSPACE_WORKTREE_REQUIRES_PROJECT_REMEDIATION,
91
+ };
92
+ }
93
+ function assertExplicitPinnedWorktreeIssueRunnable(input) {
94
+ const settings = parseIssueExecutionWorkspaceSettings(input.executionWorkspaceSettings);
95
+ const mode = settings?.mode;
96
+ if (mode !== "isolated_workspace" && mode !== "operator_branch")
97
+ return;
98
+ const resolvedMode = mode;
99
+ if (isUnrunnableWorktreeCombo({
100
+ issue: {
101
+ projectId: input.projectId ?? null,
102
+ projectWorkspaceId: input.projectWorkspaceId ?? null,
103
+ executionWorkspaceId: input.executionWorkspaceId ?? null,
104
+ executionWorkspacePreference: input.executionWorkspacePreference ?? null,
105
+ },
106
+ resolvedMode,
107
+ resolvedStrategy: resolvePinnedIssueWorkspaceStrategyType({
108
+ mode: resolvedMode,
109
+ issueSettings: settings,
110
+ }),
111
+ hasResolvablePriorSessionWorkspace: false,
112
+ })) {
113
+ throw unprocessable(WORKSPACE_WORKTREE_REQUIRES_PROJECT_MESSAGE, workspaceWorktreeRequiresProjectDetails());
114
+ }
115
+ }
61
116
  function readStringFromRecord(record, key) {
62
117
  if (!record || typeof record !== "object")
63
118
  return null;
64
119
  const value = record[key];
65
120
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
66
121
  }
122
+ async function resolveResponsibleUserIdForIssueCreate(reader, companyId, input) {
123
+ const explicitResponsibleUserId = readStringFromRecord(input, "explicitResponsibleUserId");
124
+ if (explicitResponsibleUserId && input.trustExplicitResponsibleUserId === true)
125
+ return explicitResponsibleUserId;
126
+ if (input.originKind === "routine_execution" && input.originRunId) {
127
+ const routineRun = await reader
128
+ .select({ responsibleUserId: routineRuns.responsibleUserId })
129
+ .from(routineRuns)
130
+ .where(and(eq(routineRuns.companyId, companyId), eq(routineRuns.id, input.originRunId)))
131
+ .then((rows) => rows[0] ?? null);
132
+ if (routineRun?.responsibleUserId)
133
+ return routineRun.responsibleUserId;
134
+ }
135
+ const actorResponsibleUserId = readStringFromRecord(input, "actorResponsibleUserId");
136
+ if (actorResponsibleUserId)
137
+ return actorResponsibleUserId;
138
+ if (input.actorRunId) {
139
+ const actorRun = await reader
140
+ .select({ responsibleUserId: heartbeatRuns.responsibleUserId })
141
+ .from(heartbeatRuns)
142
+ .where(and(eq(heartbeatRuns.companyId, companyId), eq(heartbeatRuns.id, input.actorRunId)))
143
+ .then((rows) => rows[0] ?? null);
144
+ if (actorRun?.responsibleUserId)
145
+ return actorRun.responsibleUserId;
146
+ }
147
+ if (input.parentId) {
148
+ const parent = await reader
149
+ .select({
150
+ responsibleUserId: issues.responsibleUserId,
151
+ createdByUserId: issues.createdByUserId,
152
+ })
153
+ .from(issues)
154
+ .where(and(eq(issues.companyId, companyId), eq(issues.id, input.parentId)))
155
+ .then((rows) => rows[0] ?? null);
156
+ if (parent?.responsibleUserId)
157
+ return parent.responsibleUserId;
158
+ if (parent?.createdByUserId)
159
+ return parent.createdByUserId;
160
+ }
161
+ return input.createdByUserId ?? null;
162
+ }
67
163
  function buildReusedExecutionWorkspaceConfigPatchFromIssueSettings(settings) {
68
164
  return {
69
165
  environmentId: settings?.environmentId ?? null,
@@ -72,6 +168,34 @@ function buildReusedExecutionWorkspaceConfigPatchFromIssueSettings(settings) {
72
168
  workspaceRuntime: settings?.workspaceRuntime ?? null,
73
169
  };
74
170
  }
171
+ // Accepted-plan children are not realized yet, so carry only unresolved
172
+ // workspace intent and let the first child run render/persist its own branch.
173
+ function buildPreRealizationExecutionWorkspaceSettings(raw) {
174
+ const settings = parseIssueExecutionWorkspaceSettings(raw, { includeEnvironmentId: true });
175
+ if (!settings)
176
+ return null;
177
+ const mode = settings.mode && settings.mode !== "inherit" && settings.mode !== "reuse_existing"
178
+ ? settings.mode
179
+ : null;
180
+ const next = {};
181
+ if (mode)
182
+ next.mode = mode;
183
+ if (settings.environmentId !== undefined)
184
+ next.environmentId = settings.environmentId;
185
+ if (settings.workspaceRuntime)
186
+ next.workspaceRuntime = settings.workspaceRuntime;
187
+ if (settings.workspaceStrategy) {
188
+ next.workspaceStrategy = {
189
+ type: settings.workspaceStrategy.type,
190
+ ...(settings.workspaceStrategy.baseRef ? { baseRef: settings.workspaceStrategy.baseRef } : {}),
191
+ ...(settings.workspaceStrategy.branchTemplate ? { branchTemplate: settings.workspaceStrategy.branchTemplate } : {}),
192
+ ...(settings.workspaceStrategy.worktreeParentDir ? { worktreeParentDir: settings.workspaceStrategy.worktreeParentDir } : {}),
193
+ ...(settings.workspaceStrategy.provisionCommand ? { provisionCommand: settings.workspaceStrategy.provisionCommand } : {}),
194
+ ...(settings.workspaceStrategy.teardownCommand ? { teardownCommand: settings.workspaceStrategy.teardownCommand } : {}),
195
+ };
196
+ }
197
+ return Object.keys(next).length > 0 ? next : null;
198
+ }
75
199
  function toTimestampMs(value) {
76
200
  if (!value)
77
201
  return null;
@@ -195,7 +319,7 @@ function sameRunLock(checkoutRunId, actorRunId) {
195
319
  return checkoutRunId === actorRunId;
196
320
  return checkoutRunId == null;
197
321
  }
198
- export const TERMINAL_HEARTBEAT_RUN_STATUSES = new Set(["succeeded", "failed", "cancelled", "timed_out"]);
322
+ export const TERMINAL_HEARTBEAT_RUN_STATUSES = new Set(["succeeded", "interrupted", "failed", "cancelled", "timed_out"]);
199
323
  const ISSUE_LIST_DESCRIPTION_MAX_CHARS = 1200;
200
324
  const ISSUE_LIST_DESCRIPTION_MAX_BYTES = ISSUE_LIST_DESCRIPTION_MAX_CHARS * 4;
201
325
  function escapeLikePattern(value) {
@@ -277,6 +401,8 @@ const ACCEPTED_PLAN_DECOMPOSITION_FINGERPRINT_CHILD_METADATA_KEYS = new Set([
277
401
  "updatedByUserId",
278
402
  "actorAgentId",
279
403
  "actorUserId",
404
+ "executionWorkspaceInheritanceMode",
405
+ "skipExecutionWorkspaceInheritance",
280
406
  ]);
281
407
  function normalizeAcceptedPlanDecompositionFingerprintChild(child) {
282
408
  return Object.fromEntries(Object.entries(child).filter(([key]) => !ACCEPTED_PLAN_DECOMPOSITION_FINGERPRINT_CHILD_METADATA_KEYS.has(key)));
@@ -1017,6 +1143,7 @@ async function liveDescendantCountMapForIssues(dbOrTx, companyId, issueIds) {
1017
1143
  JOIN heartbeat_runs live_run ON live_run.id = live_issue.execution_run_id
1018
1144
  WHERE live_issue.company_id = ${companyId}
1019
1145
  AND live_issue.hidden_at IS NULL
1146
+ AND live_issue.harness_kind IS NULL
1020
1147
  AND live_run.company_id = ${companyId}
1021
1148
  AND live_run.status IN ('queued', 'running')
1022
1149
  UNION
@@ -1025,6 +1152,7 @@ async function liveDescendantCountMapForIssues(dbOrTx, companyId, issueIds) {
1025
1152
  JOIN issues live_issue ON live_issue.id::text = (live_run.context_snapshot ->> 'issueId')
1026
1153
  WHERE live_issue.company_id = ${companyId}
1027
1154
  AND live_issue.hidden_at IS NULL
1155
+ AND live_issue.harness_kind IS NULL
1028
1156
  AND live_run.company_id = ${companyId}
1029
1157
  AND live_run.status IN ('queued', 'running')
1030
1158
  ),
@@ -1034,6 +1162,7 @@ async function liveDescendantCountMapForIssues(dbOrTx, companyId, issueIds) {
1034
1162
  JOIN issues parent ON parent.id = live_issues.parent_id
1035
1163
  WHERE parent.company_id = ${companyId}
1036
1164
  AND parent.hidden_at IS NULL
1165
+ AND parent.harness_kind IS NULL
1037
1166
  UNION ALL
1038
1167
  SELECT
1039
1168
  live_ancestors.live_issue_id,
@@ -1044,6 +1173,7 @@ async function liveDescendantCountMapForIssues(dbOrTx, companyId, issueIds) {
1044
1173
  JOIN issues parent ON parent.id = live_ancestors.next_parent_id
1045
1174
  WHERE parent.company_id = ${companyId}
1046
1175
  AND parent.hidden_at IS NULL
1176
+ AND parent.harness_kind IS NULL
1047
1177
  AND NOT parent.id = ANY(live_ancestors.visited_issue_ids)
1048
1178
  )
1049
1179
  SELECT
@@ -1203,7 +1333,7 @@ async function listIssueProductivityReviewMap(dbOrTx, companyId, sourceIssueIds)
1203
1333
  updatedAt: issues.updatedAt,
1204
1334
  })
1205
1335
  .from(issues)
1206
- .where(and(eq(issues.companyId, companyId), eq(issues.originKind, PRODUCTIVITY_REVIEW_ORIGIN_KIND), inArray(issues.originId, chunk), isNull(issues.hiddenAt), notInArray(issues.status, PRODUCTIVITY_REVIEW_TERMINAL_STATUSES)))
1336
+ .where(and(eq(issues.companyId, companyId), eq(issues.originKind, PRODUCTIVITY_REVIEW_ORIGIN_KIND), inArray(issues.originId, chunk), visibleIssueCondition(), notInArray(issues.status, PRODUCTIVITY_REVIEW_TERMINAL_STATUSES)))
1207
1337
  .orderBy(desc(issues.createdAt), desc(issues.id));
1208
1338
  reviewRows.push(...rows);
1209
1339
  }
@@ -1400,7 +1530,7 @@ async function listIssueBlockerAttentionMap(dbOrTx, companyId, issueRows) {
1400
1530
  const recoveryRows = await dbOrTx
1401
1531
  .select({ id: issues.id, originId: issues.originId })
1402
1532
  .from(issues)
1403
- .where(and(eq(issues.companyId, companyId), eq(issues.originKind, BLOCKER_ATTENTION_OPEN_RECOVERY_ORIGIN_KIND), isNull(issues.hiddenAt), notInArray(issues.status, BLOCKER_ATTENTION_OPEN_RECOVERY_TERMINAL_STATUSES)));
1533
+ .where(and(eq(issues.companyId, companyId), eq(issues.originKind, BLOCKER_ATTENTION_OPEN_RECOVERY_ORIGIN_KIND), visibleIssueCondition(), notInArray(issues.status, BLOCKER_ATTENTION_OPEN_RECOVERY_TERMINAL_STATUSES)));
1404
1534
  for (const row of recoveryRows) {
1405
1535
  const parsed = parseIssueGraphLivenessIncidentKey(row.originId);
1406
1536
  if (!parsed || parsed.companyId !== companyId)
@@ -1576,6 +1706,7 @@ const issueListSelect = {
1576
1706
  `,
1577
1707
  status: issues.status,
1578
1708
  workMode: issues.workMode,
1709
+ harnessKind: issues.harnessKind,
1579
1710
  priority: issues.priority,
1580
1711
  assigneeAgentId: issues.assigneeAgentId,
1581
1712
  assigneeUserId: issues.assigneeUserId,
@@ -1585,6 +1716,7 @@ const issueListSelect = {
1585
1716
  executionLockedAt: issues.executionLockedAt,
1586
1717
  createdByAgentId: issues.createdByAgentId,
1587
1718
  createdByUserId: issues.createdByUserId,
1719
+ responsibleUserId: issues.responsibleUserId,
1588
1720
  issueNumber: issues.issueNumber,
1589
1721
  identifier: issues.identifier,
1590
1722
  originKind: issues.originKind,
@@ -1984,7 +2116,7 @@ async function listIssueBlockedInboxAttentionMap(dbOrTx, companyId, issueRows) {
1984
2116
  dbOrTx
1985
2117
  .select()
1986
2118
  .from(issues)
1987
- .where(and(eq(issues.companyId, companyId), isNull(issues.hiddenAt), notInArray(issues.status, [...BLOCKED_INBOX_TERMINAL_STATUSES]))),
2119
+ .where(and(eq(issues.companyId, companyId), visibleIssueCondition(), notInArray(issues.status, [...BLOCKED_INBOX_TERMINAL_STATUSES]))),
1988
2120
  dbOrTx
1989
2121
  .select({
1990
2122
  companyId: issueRelations.companyId,
@@ -2345,7 +2477,7 @@ function assertValidAssigneeAgentFilter(assigneeAgentFilter) {
2345
2477
  async function blockedInboxIssueConditions(dbOrTx, companyId, filters) {
2346
2478
  const conditions = [
2347
2479
  eq(issues.companyId, companyId),
2348
- isNull(issues.hiddenAt),
2480
+ visibleIssueCondition(),
2349
2481
  notInArray(issues.status, [...BLOCKED_INBOX_TERMINAL_STATUSES]),
2350
2482
  ];
2351
2483
  const touchedByUserId = filters?.touchedByUserId?.trim() || undefined;
@@ -3268,7 +3400,7 @@ export function issueService(db) {
3268
3400
  includeBlockedInboxAttention: true,
3269
3401
  });
3270
3402
  }
3271
- const conditions = [eq(issues.companyId, companyId)];
3403
+ const conditions = [eq(issues.companyId, companyId), visibleIssueCondition()];
3272
3404
  const assigneeAgentFilter = parseIssueAssigneeAgentFilter(filters?.assigneeAgentId);
3273
3405
  assertValidAssigneeAgentFilter(assigneeAgentFilter);
3274
3406
  const limit = typeof filters?.limit === "number" && Number.isFinite(filters.limit)
@@ -3390,7 +3522,6 @@ export function issueService(db) {
3390
3522
  if (filters?.excludeRoutineExecutions && !filters?.originKind && !filters?.originId) {
3391
3523
  conditions.push(ne(issues.originKind, "routine_execution"));
3392
3524
  }
3393
- conditions.push(isNull(issues.hiddenAt));
3394
3525
  const priorityOrder = sql `CASE ${issues.priority} WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END`;
3395
3526
  const searchOrder = sql `
3396
3527
  CASE
@@ -3495,7 +3626,7 @@ export function issueService(db) {
3495
3626
  if (filters?.attention === "blocked") {
3496
3627
  return countBlockedInboxIssues(db, companyId, filters);
3497
3628
  }
3498
- const conditions = [eq(issues.companyId, companyId), isNull(issues.hiddenAt)];
3629
+ const conditions = [eq(issues.companyId, companyId), visibleIssueCondition()];
3499
3630
  const statuses = parseStatusFilter(filters?.status);
3500
3631
  if (statuses.length === 1)
3501
3632
  conditions.push(eq(issues.status, statuses[0]));
@@ -3540,7 +3671,7 @@ export function issueService(db) {
3540
3671
  countUnreadTouchedByUser: async (companyId, userId, status) => {
3541
3672
  const conditions = [
3542
3673
  eq(issues.companyId, companyId),
3543
- isNull(issues.hiddenAt),
3674
+ visibleIssueCondition(),
3544
3675
  nonPluginOperationIssueCondition(),
3545
3676
  unreadForUserCondition(companyId, userId),
3546
3677
  ];
@@ -3648,6 +3779,348 @@ export function issueService(db) {
3648
3779
  const relations = await getIssueRelationSummaryMap(issue.companyId, [issueId], db);
3649
3780
  return relations.get(issueId) ?? { blockedBy: [], blocks: [] };
3650
3781
  },
3782
+ getBlockerDiagnostics: async (issueId, maxBlockers = ISSUE_BLOCKER_DIAGNOSTICS_MAX_BLOCKERS) => {
3783
+ const issue = await db
3784
+ .select({ id: issues.id, companyId: issues.companyId })
3785
+ .from(issues)
3786
+ .where(eq(issues.id, issueId))
3787
+ .then((rows) => rows[0] ?? null);
3788
+ if (!issue)
3789
+ throw notFound("Issue not found");
3790
+ const cappedMax = Math.max(0, Math.min(maxBlockers, ISSUE_BLOCKER_DIAGNOSTICS_MAX_BLOCKERS));
3791
+ const blockerRows = await db
3792
+ .select({
3793
+ id: issues.id,
3794
+ companyId: issues.companyId,
3795
+ projectId: issues.projectId,
3796
+ parentId: issues.parentId,
3797
+ identifier: issues.identifier,
3798
+ title: issues.title,
3799
+ status: issues.status,
3800
+ priority: issues.priority,
3801
+ assigneeAgentId: issues.assigneeAgentId,
3802
+ assigneeUserId: issues.assigneeUserId,
3803
+ })
3804
+ .from(issueRelations)
3805
+ .innerJoin(issues, eq(issueRelations.issueId, issues.id))
3806
+ .where(and(eq(issueRelations.companyId, issue.companyId), eq(issueRelations.type, "blocks"), eq(issueRelations.relatedIssueId, issue.id), eq(issues.companyId, issue.companyId)))
3807
+ .orderBy(asc(issues.title), asc(issues.id))
3808
+ .limit(cappedMax + 1);
3809
+ const readiness = await listIssueDependencyReadinessMap(db, issue.companyId, [issue.id]);
3810
+ return {
3811
+ blockers: blockerRows.slice(0, cappedMax),
3812
+ readiness: readiness.get(issue.id) ?? createIssueDependencyReadiness(issue.id),
3813
+ truncated: blockerRows.length > cappedMax,
3814
+ };
3815
+ },
3816
+ getWakeDiagnostics: async (issueId, opts) => {
3817
+ const issue = await db
3818
+ .select({ id: issues.id, companyId: issues.companyId })
3819
+ .from(issues)
3820
+ .where(eq(issues.id, issueId))
3821
+ .then((rows) => rows[0] ?? null);
3822
+ if (!issue)
3823
+ throw notFound("Issue not found");
3824
+ const maxWakeRequests = Math.max(0, Math.min(opts?.maxWakeRequests ?? ISSUE_WAKE_DIAGNOSTICS_MAX_WAKE_REQUESTS, ISSUE_WAKE_DIAGNOSTICS_MAX_WAKE_REQUESTS));
3825
+ const maxActivityRecords = Math.max(0, Math.min(opts?.maxActivityRecords ?? ISSUE_WAKE_DIAGNOSTICS_MAX_ACTIVITY_RECORDS, ISSUE_WAKE_DIAGNOSTICS_MAX_ACTIVITY_RECORDS));
3826
+ const lookbackDays = Math.max(1, Math.min(opts?.lookbackDays ?? ISSUE_WAKE_DIAGNOSTICS_LOOKBACK_DAYS, ISSUE_WAKE_DIAGNOSTICS_LOOKBACK_DAYS));
3827
+ const since = new Date(Date.now() - lookbackDays * 24 * 60 * 60 * 1000);
3828
+ const wakeRows = await db
3829
+ .select({
3830
+ agentId: agentWakeupRequests.agentId,
3831
+ source: agentWakeupRequests.source,
3832
+ reason: agentWakeupRequests.reason,
3833
+ status: agentWakeupRequests.status,
3834
+ coalescedCount: agentWakeupRequests.coalescedCount,
3835
+ runId: agentWakeupRequests.runId,
3836
+ requestedAt: agentWakeupRequests.requestedAt,
3837
+ claimedAt: agentWakeupRequests.claimedAt,
3838
+ finishedAt: agentWakeupRequests.finishedAt,
3839
+ error: agentWakeupRequests.error,
3840
+ })
3841
+ .from(agentWakeupRequests)
3842
+ .where(and(eq(agentWakeupRequests.companyId, issue.companyId), gte(agentWakeupRequests.requestedAt, since), wakeRequestTargetsIssue(issue.id)))
3843
+ .orderBy(desc(agentWakeupRequests.requestedAt), desc(agentWakeupRequests.createdAt))
3844
+ .limit(maxWakeRequests + 1);
3845
+ const activityRows = await db
3846
+ .select({
3847
+ action: activityLog.action,
3848
+ entityType: activityLog.entityType,
3849
+ entityId: activityLog.entityId,
3850
+ agentId: activityLog.agentId,
3851
+ runId: activityLog.runId,
3852
+ details: activityLog.details,
3853
+ createdAt: activityLog.createdAt,
3854
+ })
3855
+ .from(activityLog)
3856
+ .where(and(eq(activityLog.companyId, issue.companyId), gte(activityLog.createdAt, since), inArray(activityLog.action, [...ISSUE_WAKE_DIAGNOSTICS_ACTIVITY_ACTIONS]), wakeDiagnosticActivityTargetsIssue(issue.id)))
3857
+ .orderBy(desc(activityLog.createdAt))
3858
+ .limit(maxActivityRecords + 1);
3859
+ return {
3860
+ wakeRequests: wakeRows.slice(0, maxWakeRequests),
3861
+ activityRecords: activityRows.slice(0, maxActivityRecords),
3862
+ truncatedWakeRequests: wakeRows.length > maxWakeRequests,
3863
+ truncatedActivityRecords: activityRows.length > maxActivityRecords,
3864
+ caps: {
3865
+ maxWakeRequests: ISSUE_WAKE_DIAGNOSTICS_MAX_WAKE_REQUESTS,
3866
+ maxActivityRecords: ISSUE_WAKE_DIAGNOSTICS_MAX_ACTIVITY_RECORDS,
3867
+ lookbackDays: ISSUE_WAKE_DIAGNOSTICS_LOOKBACK_DAYS,
3868
+ },
3869
+ };
3870
+ },
3871
+ getSubtreeDiagnostics: async (issueId, opts) => {
3872
+ const issue = await db
3873
+ .select({ id: issues.id, companyId: issues.companyId })
3874
+ .from(issues)
3875
+ .where(eq(issues.id, issueId))
3876
+ .then((rows) => rows[0] ?? null);
3877
+ if (!issue)
3878
+ throw notFound("Issue not found");
3879
+ const maxDepth = Math.max(0, Math.min(opts?.maxDepth ?? ISSUE_SUBTREE_DIAGNOSTICS_MAX_DEPTH, ISSUE_SUBTREE_DIAGNOSTICS_MAX_DEPTH));
3880
+ const maxNodes = Math.max(1, Math.min(opts?.maxNodes ?? ISSUE_SUBTREE_DIAGNOSTICS_MAX_NODES, ISSUE_SUBTREE_DIAGNOSTICS_MAX_NODES));
3881
+ const maxBlockersPerNode = Math.max(0, Math.min(opts?.maxBlockersPerNode ?? ISSUE_SUBTREE_DIAGNOSTICS_MAX_BLOCKERS_PER_NODE, ISSUE_SUBTREE_DIAGNOSTICS_MAX_BLOCKERS_PER_NODE));
3882
+ const maxWakeRequestsPerNode = Math.max(0, Math.min(opts?.maxWakeRequestsPerNode ?? ISSUE_SUBTREE_DIAGNOSTICS_MAX_WAKE_REQUESTS_PER_NODE, ISSUE_SUBTREE_DIAGNOSTICS_MAX_WAKE_REQUESTS_PER_NODE));
3883
+ const maxActivityRecordsPerNode = Math.max(0, Math.min(opts?.maxActivityRecordsPerNode ?? ISSUE_SUBTREE_DIAGNOSTICS_MAX_ACTIVITY_RECORDS_PER_NODE, ISSUE_SUBTREE_DIAGNOSTICS_MAX_ACTIVITY_RECORDS_PER_NODE));
3884
+ const lookbackDays = Math.max(1, Math.min(opts?.lookbackDays ?? ISSUE_WAKE_DIAGNOSTICS_LOOKBACK_DAYS, ISSUE_WAKE_DIAGNOSTICS_LOOKBACK_DAYS));
3885
+ const since = new Date(Date.now() - lookbackDays * 24 * 60 * 60 * 1000);
3886
+ const sinceIso = since.toISOString();
3887
+ const rawSubtreeRows = await db.execute(sql `
3888
+ WITH RECURSIVE issue_tree AS (
3889
+ SELECT
3890
+ id,
3891
+ company_id,
3892
+ project_id,
3893
+ parent_id,
3894
+ identifier,
3895
+ title,
3896
+ status,
3897
+ priority,
3898
+ assignee_agent_id,
3899
+ assignee_user_id,
3900
+ created_at,
3901
+ updated_at,
3902
+ 0 AS depth,
3903
+ ARRAY[id] AS path
3904
+ FROM issues
3905
+ WHERE company_id = ${issue.companyId}
3906
+ AND id = ${issue.id}
3907
+ AND hidden_at IS NULL
3908
+ AND harness_kind IS NULL
3909
+ UNION ALL
3910
+ SELECT
3911
+ child.id,
3912
+ child.company_id,
3913
+ child.project_id,
3914
+ child.parent_id,
3915
+ child.identifier,
3916
+ child.title,
3917
+ child.status,
3918
+ child.priority,
3919
+ child.assignee_agent_id,
3920
+ child.assignee_user_id,
3921
+ child.created_at,
3922
+ child.updated_at,
3923
+ issue_tree.depth + 1,
3924
+ issue_tree.path || child.id
3925
+ FROM issues child
3926
+ JOIN issue_tree ON child.parent_id = issue_tree.id
3927
+ WHERE child.company_id = ${issue.companyId}
3928
+ AND child.hidden_at IS NULL
3929
+ AND child.harness_kind IS NULL
3930
+ AND issue_tree.depth < ${maxDepth + 1}
3931
+ AND NOT child.id = ANY(issue_tree.path)
3932
+ )
3933
+ SELECT
3934
+ id,
3935
+ company_id AS "companyId",
3936
+ project_id AS "projectId",
3937
+ parent_id AS "parentId",
3938
+ identifier,
3939
+ title,
3940
+ status,
3941
+ priority,
3942
+ assignee_agent_id AS "assigneeAgentId",
3943
+ assignee_user_id AS "assigneeUserId",
3944
+ created_at AS "createdAt",
3945
+ updated_at AS "updatedAt",
3946
+ depth::int AS depth
3947
+ FROM issue_tree
3948
+ ORDER BY depth ASC, created_at ASC, id ASC
3949
+ LIMIT ${maxNodes + 1}
3950
+ `);
3951
+ const subtreeRows = Array.from(rawSubtreeRows)
3952
+ .map((row) => ({ ...row, depth: Number(row.depth) }));
3953
+ const rowsWithinDepth = subtreeRows.filter((row) => row.depth <= maxDepth);
3954
+ const nodes = rowsWithinDepth.slice(0, maxNodes);
3955
+ const truncatedNodes = rowsWithinDepth.length > maxNodes;
3956
+ const truncatedDepth = truncatedNodes || subtreeRows.some((row) => row.depth > maxDepth);
3957
+ const nodeIds = nodes.map((node) => node.id);
3958
+ const readiness = nodeIds.length > 0
3959
+ ? await listIssueDependencyReadinessMap(db, issue.companyId, nodeIds)
3960
+ : new Map();
3961
+ const blockersByIssueId = new Map();
3962
+ const wakeRequestsByIssueId = new Map();
3963
+ const activityRecordsByIssueId = new Map();
3964
+ const truncatedBlockerIssueIds = new Set();
3965
+ const truncatedWakeIssueIds = new Set();
3966
+ const truncatedActivityIssueIds = new Set();
3967
+ if (nodeIds.length > 0) {
3968
+ const nodeIdValues = sql.join(nodeIds.map((id) => sql `${id}`), sql `, `);
3969
+ const rawBlockerRows = Array.from(await db.execute(sql `
3970
+ WITH blocker_rows AS (
3971
+ SELECT
3972
+ blocker.id,
3973
+ blocker.company_id AS "companyId",
3974
+ blocker.project_id AS "projectId",
3975
+ blocker.parent_id AS "parentId",
3976
+ blocker.identifier,
3977
+ blocker.title,
3978
+ blocker.status,
3979
+ blocker.priority,
3980
+ blocker.assignee_agent_id AS "assigneeAgentId",
3981
+ blocker.assignee_user_id AS "assigneeUserId",
3982
+ relation.related_issue_id AS "blockedIssueId",
3983
+ relation.created_at AS "relationCreatedAt",
3984
+ row_number() OVER (
3985
+ PARTITION BY relation.related_issue_id
3986
+ ORDER BY blocker.title ASC, blocker.id ASC
3987
+ )::int AS "rowNumber"
3988
+ FROM issue_relations relation
3989
+ INNER JOIN issues blocker ON blocker.id = relation.issue_id
3990
+ WHERE relation.company_id = ${issue.companyId}
3991
+ AND relation.type = 'blocks'
3992
+ AND blocker.company_id = ${issue.companyId}
3993
+ AND blocker.hidden_at IS NULL
3994
+ AND blocker.harness_kind IS NULL
3995
+ AND relation.related_issue_id::text IN (${nodeIdValues})
3996
+ )
3997
+ SELECT *
3998
+ FROM blocker_rows
3999
+ WHERE "rowNumber" <= ${maxBlockersPerNode + 1}
4000
+ ORDER BY "blockedIssueId" ASC, "rowNumber" ASC
4001
+ `));
4002
+ for (const row of rawBlockerRows) {
4003
+ const normalized = { ...row, rowNumber: Number(row.rowNumber) };
4004
+ if (normalized.rowNumber > maxBlockersPerNode) {
4005
+ truncatedBlockerIssueIds.add(normalized.blockedIssueId);
4006
+ continue;
4007
+ }
4008
+ const rows = blockersByIssueId.get(normalized.blockedIssueId) ?? [];
4009
+ rows.push(normalized);
4010
+ blockersByIssueId.set(normalized.blockedIssueId, rows);
4011
+ }
4012
+ const wakeTargetIssueIdSql = sql `
4013
+ coalesce(
4014
+ wake.payload ->> 'issueId',
4015
+ wake.payload ->> 'taskId',
4016
+ wake.payload -> '_paperclipWakeContext' ->> 'issueId',
4017
+ wake.payload -> '_paperclipWakeContext' ->> 'taskId'
4018
+ )
4019
+ `;
4020
+ const rawWakeRows = Array.from(await db.execute(sql `
4021
+ WITH wake_rows AS (
4022
+ SELECT
4023
+ ${wakeTargetIssueIdSql} AS "issueId",
4024
+ wake.agent_id AS "agentId",
4025
+ wake.source,
4026
+ wake.reason,
4027
+ wake.status,
4028
+ wake.coalesced_count AS "coalescedCount",
4029
+ wake.run_id AS "runId",
4030
+ wake.requested_at AS "requestedAt",
4031
+ wake.claimed_at AS "claimedAt",
4032
+ wake.finished_at AS "finishedAt",
4033
+ wake.error,
4034
+ row_number() OVER (
4035
+ PARTITION BY ${wakeTargetIssueIdSql}
4036
+ ORDER BY wake.requested_at DESC, wake.created_at DESC
4037
+ )::int AS "rowNumber"
4038
+ FROM agent_wakeup_requests wake
4039
+ WHERE wake.company_id = ${issue.companyId}
4040
+ AND wake.requested_at >= ${sinceIso}::timestamptz
4041
+ AND ${wakeTargetIssueIdSql} IN (${nodeIdValues})
4042
+ )
4043
+ SELECT *
4044
+ FROM wake_rows
4045
+ WHERE "rowNumber" <= ${maxWakeRequestsPerNode + 1}
4046
+ ORDER BY "issueId" ASC, "requestedAt" DESC
4047
+ `));
4048
+ for (const row of rawWakeRows) {
4049
+ const normalized = { ...row, rowNumber: Number(row.rowNumber) };
4050
+ if (normalized.rowNumber > maxWakeRequestsPerNode) {
4051
+ truncatedWakeIssueIds.add(normalized.issueId);
4052
+ continue;
4053
+ }
4054
+ const rows = wakeRequestsByIssueId.get(normalized.issueId) ?? [];
4055
+ rows.push(normalized);
4056
+ wakeRequestsByIssueId.set(normalized.issueId, rows);
4057
+ }
4058
+ const activityTargetIssueIdSql = sql `
4059
+ coalesce(
4060
+ CASE WHEN activity.entity_type = 'issue' THEN activity.entity_id ELSE NULL END,
4061
+ activity.details ->> 'issueId',
4062
+ activity.details ->> 'rootIssueId'
4063
+ )
4064
+ `;
4065
+ const activityActionValues = sql.join(ISSUE_WAKE_DIAGNOSTICS_ACTIVITY_ACTIONS.map((action) => sql `${action}`), sql `, `);
4066
+ const rawActivityRows = Array.from(await db.execute(sql `
4067
+ WITH activity_rows AS (
4068
+ SELECT
4069
+ ${activityTargetIssueIdSql} AS "issueId",
4070
+ activity.action,
4071
+ activity.entity_type AS "entityType",
4072
+ activity.entity_id AS "entityId",
4073
+ activity.agent_id AS "agentId",
4074
+ activity.run_id AS "runId",
4075
+ activity.details,
4076
+ activity.created_at AS "createdAt",
4077
+ row_number() OVER (
4078
+ PARTITION BY ${activityTargetIssueIdSql}
4079
+ ORDER BY activity.created_at DESC, activity.id DESC
4080
+ )::int AS "rowNumber"
4081
+ FROM activity_log activity
4082
+ WHERE activity.company_id = ${issue.companyId}
4083
+ AND activity.created_at >= ${sinceIso}::timestamptz
4084
+ AND activity.action IN (${activityActionValues})
4085
+ AND ${activityTargetIssueIdSql} IN (${nodeIdValues})
4086
+ )
4087
+ SELECT *
4088
+ FROM activity_rows
4089
+ WHERE "rowNumber" <= ${maxActivityRecordsPerNode + 1}
4090
+ ORDER BY "issueId" ASC, "createdAt" DESC
4091
+ `));
4092
+ for (const row of rawActivityRows) {
4093
+ const normalized = { ...row, rowNumber: Number(row.rowNumber) };
4094
+ if (normalized.rowNumber > maxActivityRecordsPerNode) {
4095
+ truncatedActivityIssueIds.add(normalized.issueId);
4096
+ continue;
4097
+ }
4098
+ const rows = activityRecordsByIssueId.get(normalized.issueId) ?? [];
4099
+ rows.push(normalized);
4100
+ activityRecordsByIssueId.set(normalized.issueId, rows);
4101
+ }
4102
+ }
4103
+ return {
4104
+ nodes,
4105
+ blockersByIssueId,
4106
+ readinessByIssueId: readiness,
4107
+ wakeRequestsByIssueId,
4108
+ activityRecordsByIssueId,
4109
+ truncatedNodes,
4110
+ truncatedDepth,
4111
+ truncatedBlockerIssueIds,
4112
+ truncatedWakeIssueIds,
4113
+ truncatedActivityIssueIds,
4114
+ caps: {
4115
+ maxDepth,
4116
+ maxNodes,
4117
+ maxBlockersPerNode,
4118
+ maxWakeRequestsPerNode,
4119
+ maxActivityRecordsPerNode,
4120
+ lookbackDays,
4121
+ },
4122
+ };
4123
+ },
3651
4124
  getDependencyReadiness: async (issueId, dbOrTx = db) => {
3652
4125
  const issue = await dbOrTx
3653
4126
  .select({ id: issues.id, companyId: issues.companyId })
@@ -3788,15 +4261,30 @@ export function issueService(db) {
3788
4261
  if (childCount >= MAX_CHILD_ISSUES_CREATED_BY_HELPER) {
3789
4262
  throw unprocessable(`Parent issue already has the maximum ${MAX_CHILD_ISSUES_CREATED_BY_HELPER} child issues for this helper`);
3790
4263
  }
3791
- const { acceptanceCriteria, blockParentUntilDone, actorAgentId, actorUserId, ...issueData } = data;
4264
+ const { acceptanceCriteria, blockParentUntilDone, executionWorkspaceInheritanceMode = "linkage", actorAgentId, actorUserId, ...issueData } = data;
4265
+ const inheritStrategyOnly = executionWorkspaceInheritanceMode === "strategy_only";
4266
+ const hasExplicitExecutionWorkspaceOverride = issueData.executionWorkspaceId !== undefined ||
4267
+ issueData.executionWorkspacePreference !== undefined ||
4268
+ issueData.executionWorkspaceSettings !== undefined;
4269
+ const inheritedPreRealizationWorkspaceSettings = inheritStrategyOnly && !hasExplicitExecutionWorkspaceOverride
4270
+ ? buildPreRealizationExecutionWorkspaceSettings(parent.executionWorkspaceSettings)
4271
+ : null;
3792
4272
  let child = await issueService(db).create(parent.companyId, {
3793
4273
  ...issueData,
3794
4274
  parentId: parent.id,
3795
4275
  projectId: issueData.projectId ?? parent.projectId,
4276
+ projectWorkspaceId: issueData.projectWorkspaceId ?? (inheritStrategyOnly ? parent.projectWorkspaceId : undefined),
3796
4277
  goalId: issueData.goalId ?? parent.goalId,
4278
+ actorResponsibleUserId: issueData.actorResponsibleUserId ?? null,
4279
+ trustExplicitResponsibleUserId: issueData.trustExplicitResponsibleUserId === true,
3797
4280
  requestDepth: clampIssueRequestDepth(Math.max(clampIssueRequestDepth(parent.requestDepth) + 1, issueData.requestDepth ?? 0)),
3798
4281
  description: appendAcceptanceCriteriaToDescription(issueData.description, acceptanceCriteria),
3799
- inheritExecutionWorkspaceFromIssueId: parent.id,
4282
+ ...(inheritedPreRealizationWorkspaceSettings
4283
+ ? { executionWorkspaceSettings: inheritedPreRealizationWorkspaceSettings }
4284
+ : {}),
4285
+ ...(inheritStrategyOnly
4286
+ ? { skipExecutionWorkspaceInheritance: true }
4287
+ : { inheritExecutionWorkspaceFromIssueId: parent.id }),
3800
4288
  });
3801
4289
  if (blockParentUntilDone) {
3802
4290
  const existingBlockers = await db
@@ -3938,7 +4426,10 @@ export function issueService(db) {
3938
4426
  if (!nextChildInput) {
3939
4427
  throw new Error("Accepted-plan decomposition child cursor moved past the requested children");
3940
4428
  }
3941
- const createdChild = await issueService(tx).createChild(sourceIssue.id, nextChildInput);
4429
+ const createdChild = await issueService(tx).createChild(sourceIssue.id, {
4430
+ ...nextChildInput,
4431
+ executionWorkspaceInheritanceMode: "strategy_only",
4432
+ });
3942
4433
  const nextIds = [...existingChildIssueIds, createdChild.issue.id];
3943
4434
  const now = new Date();
3944
4435
  const nextStatus = nextIds.length === data.children.length ? "completed" : "in_flight";
@@ -4046,7 +4537,7 @@ export function issueService(db) {
4046
4537
  });
4047
4538
  },
4048
4539
  create: async (companyId, data) => {
4049
- const { labelIds: inputLabelIds, blockedByIssueIds, inheritExecutionWorkspaceFromIssueId, watchdog, watchdogActorRunId, ...issueData } = data;
4540
+ const { labelIds: inputLabelIds, blockedByIssueIds, inheritExecutionWorkspaceFromIssueId, skipExecutionWorkspaceInheritance, watchdog, watchdogActorRunId, actorRunId, actorResponsibleUserId, trustExplicitResponsibleUserId, ...issueData } = data;
4050
4541
  const isolatedWorkspacesEnabled = (await instanceSettings.getExperimental()).enableIsolatedWorkspaces;
4051
4542
  if (!isolatedWorkspacesEnabled) {
4052
4543
  delete issueData.executionWorkspaceId;
@@ -4071,7 +4562,9 @@ export function issueService(db) {
4071
4562
  let executionWorkspaceId = issueData.executionWorkspaceId ?? null;
4072
4563
  let executionWorkspacePreference = issueData.executionWorkspacePreference ?? null;
4073
4564
  let executionWorkspaceSettings = issueData.executionWorkspaceSettings ?? null;
4074
- const workspaceInheritanceIssueId = inheritExecutionWorkspaceFromIssueId ?? issueData.parentId ?? null;
4565
+ const workspaceInheritanceIssueId = skipExecutionWorkspaceInheritance
4566
+ ? null
4567
+ : inheritExecutionWorkspaceFromIssueId ?? issueData.parentId ?? null;
4075
4568
  const hasExplicitExecutionWorkspaceOverride = issueData.executionWorkspaceId !== undefined ||
4076
4569
  issueData.executionWorkspacePreference !== undefined ||
4077
4570
  issueData.executionWorkspaceSettings !== undefined;
@@ -4162,6 +4655,15 @@ export function issueService(db) {
4162
4655
  if (executionWorkspaceId) {
4163
4656
  await assertValidExecutionWorkspace(companyId, issueData.projectId, executionWorkspaceId, tx);
4164
4657
  }
4658
+ if (isolatedWorkspacesEnabled && issueData.executionWorkspaceSettings !== undefined) {
4659
+ assertExplicitPinnedWorktreeIssueRunnable({
4660
+ projectId: issueData.projectId ?? null,
4661
+ projectWorkspaceId,
4662
+ executionWorkspaceId,
4663
+ executionWorkspacePreference,
4664
+ executionWorkspaceSettings: issueData.executionWorkspaceSettings,
4665
+ });
4666
+ }
4165
4667
  // Self-correcting counter: use MAX(issue_number) + 1 if the counter
4166
4668
  // has drifted below the actual max, preventing identifier collisions.
4167
4669
  const [maxRow] = await tx
@@ -4178,8 +4680,19 @@ export function issueService(db) {
4178
4680
  .returning({ issueCounter: companies.issueCounter, issuePrefix: companies.issuePrefix });
4179
4681
  const issueNumber = company.issueCounter;
4180
4682
  const identifier = `${company.issuePrefix}-${issueNumber}`;
4683
+ const responsibleUserId = await resolveResponsibleUserIdForIssueCreate(tx, companyId, {
4684
+ explicitResponsibleUserId: issueData.responsibleUserId ?? null,
4685
+ createdByUserId: issueData.createdByUserId ?? null,
4686
+ parentId: issueData.parentId ?? null,
4687
+ originKind: issueData.originKind ?? "manual",
4688
+ originRunId: issueData.originRunId ?? null,
4689
+ actorRunId: actorRunId ?? null,
4690
+ actorResponsibleUserId: actorResponsibleUserId ?? null,
4691
+ trustExplicitResponsibleUserId: trustExplicitResponsibleUserId === true,
4692
+ });
4181
4693
  const values = {
4182
4694
  ...issueData,
4695
+ responsibleUserId,
4183
4696
  requestDepth: clampIssueRequestDepth(issueData.requestDepth),
4184
4697
  originKind: issueData.originKind ?? "manual",
4185
4698
  goalId: resolveIssueGoalId({
@@ -4324,6 +4837,15 @@ export function issueService(db) {
4324
4837
  await assertValidExecutionWorkspace(existing.companyId, nextProjectId, nextExecutionWorkspaceId);
4325
4838
  }
4326
4839
  }
4840
+ if (isolatedWorkspacesEnabled && issueData.executionWorkspaceSettings !== undefined) {
4841
+ assertExplicitPinnedWorktreeIssueRunnable({
4842
+ projectId: nextProjectId ?? null,
4843
+ projectWorkspaceId: nextProjectWorkspaceId ?? null,
4844
+ executionWorkspaceId: nextExecutionWorkspaceId ?? null,
4845
+ executionWorkspacePreference: nextExecutionWorkspacePreference ?? null,
4846
+ executionWorkspaceSettings: issueData.executionWorkspaceSettings,
4847
+ });
4848
+ }
4327
4849
  applyStatusSideEffects(issueData.status, patch);
4328
4850
  if (issueData.status && issueData.status !== "done") {
4329
4851
  patch.completedAt = null;
@@ -4422,7 +4944,7 @@ export function issueService(db) {
4422
4944
  .where(eq(issues.companyId, companyId));
4423
4945
  let cleared = 0;
4424
4946
  for (const row of rows) {
4425
- const settings = parseIssueExecutionWorkspaceSettings(row.executionWorkspaceSettings);
4947
+ const settings = parseIssueExecutionWorkspaceSettings(row.executionWorkspaceSettings, { includeEnvironmentId: true });
4426
4948
  if (settings?.environmentId !== environmentId)
4427
4949
  continue;
4428
4950
  await db