@penclipai/server 2026.531.0 → 2026.602.0-canary.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 (110) hide show
  1. package/dist/attachment-types.d.ts.map +1 -1
  2. package/dist/attachment-types.js +8 -1
  3. package/dist/attachment-types.js.map +1 -1
  4. package/dist/onboarding-assets/default/AGENTS.md +1 -0
  5. package/dist/routes/issues.d.ts.map +1 -1
  6. package/dist/routes/issues.js +120 -9
  7. package/dist/routes/issues.js.map +1 -1
  8. package/dist/routes/plugins.d.ts.map +1 -1
  9. package/dist/routes/plugins.js +41 -2
  10. package/dist/routes/plugins.js.map +1 -1
  11. package/dist/services/npm-command.d.ts +10 -0
  12. package/dist/services/npm-command.d.ts.map +1 -1
  13. package/dist/services/npm-command.js +39 -0
  14. package/dist/services/npm-command.js.map +1 -1
  15. package/dist/services/plugin-loader.d.ts.map +1 -1
  16. package/dist/services/plugin-loader.js +114 -6
  17. package/dist/services/plugin-loader.js.map +1 -1
  18. package/dist/storage/local-disk-provider.d.ts.map +1 -1
  19. package/dist/storage/local-disk-provider.js +8 -2
  20. package/dist/storage/local-disk-provider.js.map +1 -1
  21. package/dist/storage/s3-provider.d.ts.map +1 -1
  22. package/dist/storage/s3-provider.js +1 -0
  23. package/dist/storage/s3-provider.js.map +1 -1
  24. package/dist/storage/service.js +2 -2
  25. package/dist/storage/service.js.map +1 -1
  26. package/dist/storage/types.d.ts +5 -1
  27. package/dist/storage/types.d.ts.map +1 -1
  28. package/package.json +17 -17
  29. package/skills/paperclip/SKILL.md +6 -0
  30. package/skills/paperclip/references/artifacts.md +44 -0
  31. package/skills/paperclip/scripts/paperclip-upload-artifact.sh +371 -0
  32. package/ui-dist/assets/{_basePickBy-ByMSfj39.js → _basePickBy-CeTFxbQW.js} +1 -1
  33. package/ui-dist/assets/{_baseUniq-DG1b_zmL.js → _baseUniq-D0ujdjSD.js} +1 -1
  34. package/ui-dist/assets/{arc-DcS9UkZl.js → arc-BO6fFqoX.js} +1 -1
  35. package/ui-dist/assets/{architectureDiagram-VXUJARFQ-D5Kff5cm.js → architectureDiagram-VXUJARFQ-D2UpP8cQ.js} +1 -1
  36. package/ui-dist/assets/{blockDiagram-VD42YOAC-BH6dSBfQ.js → blockDiagram-VD42YOAC-BR95g_Bq.js} +1 -1
  37. package/ui-dist/assets/{browser-ponyfill-BfYTcaXM.js → browser-ponyfill-f87cfQ5P.js} +1 -1
  38. package/ui-dist/assets/{c4Diagram-YG6GDRKO-BAf-ehBE.js → c4Diagram-YG6GDRKO-DI5tPMqa.js} +1 -1
  39. package/ui-dist/assets/channel-CET4O6ry.js +1 -0
  40. package/ui-dist/assets/{chunk-4BX2VUAB-C9391Aki.js → chunk-4BX2VUAB-DYVTUDCW.js} +1 -1
  41. package/ui-dist/assets/{chunk-55IACEB6-6rL-ZsOn.js → chunk-55IACEB6-D0QGIKOI.js} +1 -1
  42. package/ui-dist/assets/{chunk-B4BG7PRW-ImljqNzx.js → chunk-B4BG7PRW-DMGouDbX.js} +1 -1
  43. package/ui-dist/assets/{chunk-DI55MBZ5-BDdh18Rg.js → chunk-DI55MBZ5-CDoOezvn.js} +1 -1
  44. package/ui-dist/assets/{chunk-FMBD7UC4-7_L2tN7X.js → chunk-FMBD7UC4-BsnMSmde.js} +1 -1
  45. package/ui-dist/assets/{chunk-QN33PNHL-CzQKfq_z.js → chunk-QN33PNHL-DakMd-Np.js} +1 -1
  46. package/ui-dist/assets/{chunk-QZHKN3VN-XF2YykJj.js → chunk-QZHKN3VN-DqQUmo7x.js} +1 -1
  47. package/ui-dist/assets/{chunk-TZMSLE5B-BwX2ntiZ.js → chunk-TZMSLE5B-BhHr3bYf.js} +1 -1
  48. package/ui-dist/assets/classDiagram-2ON5EDUG-D0t_5_AY.js +1 -0
  49. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-D0t_5_AY.js +1 -0
  50. package/ui-dist/assets/clone-CsJH_z-2.js +1 -0
  51. package/ui-dist/assets/{cose-bilkent-S5V4N54A-BbH4008b.js → cose-bilkent-S5V4N54A-Cu5Xt36m.js} +1 -1
  52. package/ui-dist/assets/{dagre-6UL2VRFP-b2pZICbR.js → dagre-6UL2VRFP-oB6IWi02.js} +1 -1
  53. package/ui-dist/assets/{diagram-PSM6KHXK-C4lbvPFi.js → diagram-PSM6KHXK-CvrdSiPO.js} +1 -1
  54. package/ui-dist/assets/{diagram-QEK2KX5R-BfpepdBy.js → diagram-QEK2KX5R-DQSpEaL6.js} +1 -1
  55. package/ui-dist/assets/{diagram-S2PKOQOG-DLVgiUi4.js → diagram-S2PKOQOG-Ckv-tSzv.js} +1 -1
  56. package/ui-dist/assets/{erDiagram-Q2GNP2WA-B2OluUW7.js → erDiagram-Q2GNP2WA-B_hA9waW.js} +1 -1
  57. package/ui-dist/assets/{flowDiagram-NV44I4VS-Cn2DdjAL.js → flowDiagram-NV44I4VS-Bb0ZY-IZ.js} +1 -1
  58. package/ui-dist/assets/{ganttDiagram-JELNMOA3-CR227Gza.js → ganttDiagram-JELNMOA3-DKwCKDGB.js} +1 -1
  59. package/ui-dist/assets/{gitGraphDiagram-V2S2FVAM-CeiCAnXp.js → gitGraphDiagram-V2S2FVAM-DAzn2J50.js} +1 -1
  60. package/ui-dist/assets/{graph-w9htXwiQ.js → graph-Cl-tjvPX.js} +1 -1
  61. package/ui-dist/assets/{index-CXLOfk6Z.js → index-8GC1rVe0.js} +1 -1
  62. package/ui-dist/assets/{index-mX6-5FRE.js → index-B4Zx0-UV.js} +1 -1
  63. package/ui-dist/assets/{index-Veai0rZp.js → index-BPtAEykT.js} +1 -1
  64. package/ui-dist/assets/{index-itLpbAYs.js → index-BsoFGxYP.js} +1 -1
  65. package/ui-dist/assets/{index-g35rE4vj.js → index-BtF-hm9b.js} +1 -1
  66. package/ui-dist/assets/{index-DE5MeDRO.js → index-C-t56Owg.js} +1 -1
  67. package/ui-dist/assets/{index-eh6Rv8FK.js → index-CQo-Yt-A.js} +1 -1
  68. package/ui-dist/assets/{index-CbL_lUhe.js → index-CbYaoEKW.js} +1 -1
  69. package/ui-dist/assets/{index-BBDrbFd2.js → index-CfPehaOb.js} +1 -1
  70. package/ui-dist/assets/{index-wbYobCWV.js → index-ChV-aw4S.js} +1 -1
  71. package/ui-dist/assets/{index-cx2uRcar.js → index-CwlKP6-n.js} +153 -153
  72. package/ui-dist/assets/{index-CghOG6Ex.js → index-DF7nqDl_.js} +1 -1
  73. package/ui-dist/assets/{index-Cuh9kSyD.js → index-DG38TZml.js} +1 -1
  74. package/ui-dist/assets/{index-BXd30uHo.js → index-DL1vj0uy.js} +1 -1
  75. package/ui-dist/assets/index-DMIAyVox.css +1 -0
  76. package/ui-dist/assets/{index-CdMaXyLo.js → index-DNDIa7NC.js} +1 -1
  77. package/ui-dist/assets/{index-9Pv0GfLY.js → index-Dl6o6n5E.js} +1 -1
  78. package/ui-dist/assets/{index-CDENxz3A.js → index-DlxftVuv.js} +1 -1
  79. package/ui-dist/assets/{index-DQlzKoOP.js → index-Do6HXiXB.js} +1 -1
  80. package/ui-dist/assets/{index-gEKPjjH6.js → index-DxJJ3F_W.js} +1 -1
  81. package/ui-dist/assets/{index-su6SxDiW.js → index-DzltSrZq.js} +1 -1
  82. package/ui-dist/assets/{index-DxCNY9q9.js → index-LLPT1gK0.js} +1 -1
  83. package/ui-dist/assets/{index-CXwrq9L0.js → index-km6491jM.js} +1 -1
  84. package/ui-dist/assets/{index-BYEl2-7l.js → index-u71Xs_3k.js} +1 -1
  85. package/ui-dist/assets/{infoDiagram-HS3SLOUP-eIIGpF4Y.js → infoDiagram-HS3SLOUP-DEL8kyRP.js} +1 -1
  86. package/ui-dist/assets/{journeyDiagram-XKPGCS4Q-C-atAVVp.js → journeyDiagram-XKPGCS4Q-CRSQwCYB.js} +1 -1
  87. package/ui-dist/assets/{kanban-definition-3W4ZIXB7-DQqhMnWt.js → kanban-definition-3W4ZIXB7-B4y2cOh8.js} +1 -1
  88. package/ui-dist/assets/{layout-Bhpcjb2T.js → layout-BpvTQ45G.js} +1 -1
  89. package/ui-dist/assets/{linear-BlYGGdYI.js → linear-CYavthmK.js} +1 -1
  90. package/ui-dist/assets/{mermaid.core-BRPNlZ-h.js → mermaid.core-CYlgTsL-.js} +4 -4
  91. package/ui-dist/assets/{mindmap-definition-VGOIOE7T-TDpHA9cf.js → mindmap-definition-VGOIOE7T-D5EKPjo-.js} +1 -1
  92. package/ui-dist/assets/{pieDiagram-ADFJNKIX-ETq0xhKM.js → pieDiagram-ADFJNKIX-C2JvyqX-.js} +1 -1
  93. package/ui-dist/assets/{quadrantDiagram-AYHSOK5B-Dtn2WJxU.js → quadrantDiagram-AYHSOK5B--5eHpwLO.js} +1 -1
  94. package/ui-dist/assets/{requirementDiagram-UZGBJVZJ-DR_U4zGO.js → requirementDiagram-UZGBJVZJ-DWl0VcDt.js} +1 -1
  95. package/ui-dist/assets/{sankeyDiagram-TZEHDZUN-Tf0xWtIZ.js → sankeyDiagram-TZEHDZUN-DTVD0t60.js} +1 -1
  96. package/ui-dist/assets/{sequenceDiagram-WL72ISMW-DNiMMozs.js → sequenceDiagram-WL72ISMW-DqRlRIie.js} +1 -1
  97. package/ui-dist/assets/{stateDiagram-FKZM4ZOC-Dnd48Ana.js → stateDiagram-FKZM4ZOC-pmJVfUSI.js} +1 -1
  98. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-tJvkm5fW.js +1 -0
  99. package/ui-dist/assets/{timeline-definition-IT6M3QCI-B5lOcm7v.js → timeline-definition-IT6M3QCI-D4a7yShw.js} +1 -1
  100. package/ui-dist/assets/{treemap-GDKQZRPO-DPalpZKu.js → treemap-GDKQZRPO-B99Tnc1-.js} +1 -1
  101. package/ui-dist/assets/{xychartDiagram-PRI3JC2R-wR9L_1vP.js → xychartDiagram-PRI3JC2R-DtVbo4uj.js} +1 -1
  102. package/ui-dist/index.html +2 -2
  103. package/ui-dist/locales/en/common.json +13 -0
  104. package/ui-dist/locales/zh-CN/common.json +13 -0
  105. package/ui-dist/assets/channel-DfI4Qn_9.js +0 -1
  106. package/ui-dist/assets/classDiagram-2ON5EDUG-CeFzDBRj.js +0 -1
  107. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-CeFzDBRj.js +0 -1
  108. package/ui-dist/assets/clone-nd1JPeva.js +0 -1
  109. package/ui-dist/assets/index-DsG7g8TR.css +0 -1
  110. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-CxR0Vtv5.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"attachment-types.d.ts","sourceRoot":"","sources":["../src/attachment-types.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAYlD,CAAC;AAEF,eAAO,MAAM,+BAA+B,6BAA6B,CAAC;AAC1E,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAChD,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAOpD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAOnE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAS1F;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGnF;AAED,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE1E;AAQD,gEAAgE;AAChE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,eAAO,MAAM,oBAAoB,QACuC,CAAC;AAEzE,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKzF"}
1
+ {"version":3,"file":"attachment-types.d.ts","sourceRoot":"","sources":["../src/attachment-types.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAgBlD,CAAC;AAEF,eAAO,MAAM,+BAA+B,6BAA6B,CAAC;AAC1E,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAChD,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAUpD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAOnE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAS1F;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGnF;AAED,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE1E;AAQD,gEAAgE;AAChE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,eAAO,MAAM,oBAAoB,QACuC,CAAC;AAEzE,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKzF"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shared attachment content-type configuration.
3
3
  *
4
- * By default a curated set of image/document/text types are allowed. Set the
4
+ * By default a curated set of image/document/text/media types are allowed. Set the
5
5
  * `PAPERCLIP_ALLOWED_ATTACHMENT_TYPES` environment variable to a
6
6
  * comma-separated list of MIME types or wildcard patterns to expand the
7
7
  * allowed set for routes that use this allowlist.
@@ -22,11 +22,15 @@ export const DEFAULT_ALLOWED_TYPES = [
22
22
  "image/webp",
23
23
  "image/gif",
24
24
  "application/pdf",
25
+ "application/zip",
25
26
  "text/markdown",
26
27
  "text/plain",
27
28
  "application/json",
28
29
  "text/csv",
29
30
  "text/html",
31
+ "video/mp4",
32
+ "video/webm",
33
+ "video/quicktime",
30
34
  ];
31
35
  export const DEFAULT_ATTACHMENT_CONTENT_TYPE = "application/octet-stream";
32
36
  export const SVG_CONTENT_TYPE = "image/svg+xml";
@@ -37,6 +41,9 @@ export const INLINE_ATTACHMENT_TYPES = [
37
41
  "text/markdown",
38
42
  "application/json",
39
43
  "text/csv",
44
+ "video/mp4",
45
+ "video/webm",
46
+ "video/quicktime",
40
47
  ];
41
48
  /**
42
49
  * Parse a comma-separated list of MIME type patterns into a normalised array.
@@ -1 +1 @@
1
- {"version":3,"file":"attachment-types.js","sourceRoot":"","sources":["../src/attachment-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"attachment-types.js","sourceRoot":"","sources":["../src/attachment-types.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ You are an agent at Paperclip company.
5
5
  - Start actionable work in the same heartbeat. Do not stop at a plan unless the issue explicitly asks for planning.
6
6
  - Keep the work moving until it is done. If you need QA to review it, ask them. If you need your boss to review it, ask them.
7
7
  - Leave durable progress in task comments, documents, or work products, then update the issue to a clear final disposition before you exit.
8
+ - When your work produces a user-inspectable file, follow the Paperclip skill's "Generated Artifacts and Work Products" workflow before final disposition. Use `skills/paperclip/scripts/paperclip-upload-artifact.sh` when working in this repo, create/update an artifact work product when the file is the deliverable, and link the uploaded attachment in the final comment. Do not rely on local filesystem paths as the only access path.
8
9
  - Comments, documents, screenshots, work products, and `Remaining` bullets are evidence, not valid liveness paths by themselves.
9
10
  - Final disposition checklist: mark `done` when complete and verified; use `in_review` only with a real reviewer, approval, interaction, or monitor path; use `blocked` only with first-class blockers or a named unblock owner/action; create delegated follow-up issues with blockers when another agent owns the next step; keep `in_progress` only when a live continuation path exists.
10
11
  - Use child issues for parallel or long delegated work instead of polling agents, sessions, or processes.
@@ -1 +1 @@
1
- {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/routes/issues.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAUxC,OAAO,EAkCL,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAI3B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAiD1D,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,0CAA0C,CAAC;AASlD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AA8BhF,KAAK,oBAAoB,GAAG;IAC1B,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACtF,CAAC;AA6rBF,wBAAgB,WAAW,CACzB,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE;IACJ,qBAAqB,CAAC,EAAE;QACtB,0BAA0B,CAAC,KAAK,CAAC,EAAE;YACjC,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,GAAG,CAAC,EAAE,IAAI,CAAC;SACZ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACtB,CAAC;IACF,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CACtC,8CAkwKP"}
1
+ {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/routes/issues.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAUxC,OAAO,EAmCL,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAI3B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAkD1D,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,0CAA0C,CAAC;AASlD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AA8BhF,KAAK,oBAAoB,GAAG;IAC1B,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACtF,CAAC;AAitBF,wBAAgB,WAAW,CACzB,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE;IACJ,qBAAqB,CAAC,EAAE;QACtB,0BAA0B,CAAC,KAAK,CAAC,EAAE;YACjC,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,GAAG,CAAC,EAAE,IAAI,CAAC;SACZ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACtB,CAAC;IACF,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CACtC,8CAs3KP"}
@@ -4,7 +4,7 @@ import multer from "multer";
4
4
  import { z } from "zod";
5
5
  import { and, desc, eq, inArray, notInArray } from "drizzle-orm";
6
6
  import { activityLog, executionWorkspaces, heartbeatRuns, issueExecutionDecisions, issueRelations, issues as issueRows, projectWorkspaces, } from "@penclipai/db";
7
- import { addIssueCommentSchema, acceptIssueThreadInteractionSchema, cancelIssueThreadInteractionSchema, companySearchQuerySchema, createIssueAttachmentMetadataSchema, createIssueThreadInteractionSchema, createIssueWorkProductSchema, createIssueLabelSchema, createAcceptedPlanDecompositionSchema, checkoutIssueSchema, createDocumentAnnotationCommentSchema, createDocumentAnnotationThreadSchema, createChildIssueSchema, createIssueSchema, resolveCreateIssueStatusDefault, resolveIssueRecoveryActionSchema, feedbackTargetTypeSchema, feedbackTraceStatusSchema, feedbackVoteValueSchema, upsertIssueFeedbackVoteSchema, linkIssueApprovalSchema, issueDocumentKeySchema, ISSUE_CONTINUATION_SUMMARY_DOCUMENT_KEY, rejectIssueThreadInteractionSchema, restoreIssueDocumentRevisionSchema, respondIssueThreadInteractionSchema, updateIssueWorkProductSchema, updateDocumentAnnotationThreadSchema, upsertIssueDocumentSchema, updateIssueSchema, getClosedIsolatedExecutionWorkspaceMessage, isClosedIsolatedExecutionWorkspace, normalizeIssueIdentifier as normalizeIssueReferenceIdentifier, } from "@penclipai/shared";
7
+ import { addIssueCommentSchema, acceptIssueThreadInteractionSchema, attachmentArtifactWorkProductMetadataSchema, cancelIssueThreadInteractionSchema, companySearchQuerySchema, createIssueAttachmentMetadataSchema, createIssueThreadInteractionSchema, createIssueWorkProductSchema, createIssueLabelSchema, createAcceptedPlanDecompositionSchema, checkoutIssueSchema, createDocumentAnnotationCommentSchema, createDocumentAnnotationThreadSchema, createChildIssueSchema, createIssueSchema, resolveCreateIssueStatusDefault, resolveIssueRecoveryActionSchema, feedbackTargetTypeSchema, feedbackTraceStatusSchema, feedbackVoteValueSchema, upsertIssueFeedbackVoteSchema, linkIssueApprovalSchema, issueDocumentKeySchema, ISSUE_CONTINUATION_SUMMARY_DOCUMENT_KEY, rejectIssueThreadInteractionSchema, restoreIssueDocumentRevisionSchema, respondIssueThreadInteractionSchema, updateIssueWorkProductSchema, updateDocumentAnnotationThreadSchema, upsertIssueDocumentSchema, updateIssueSchema, getClosedIsolatedExecutionWorkspaceMessage, isClosedIsolatedExecutionWorkspace, normalizeIssueIdentifier as normalizeIssueReferenceIdentifier, } from "@penclipai/shared";
8
8
  import { getTelemetryClient } from "../telemetry.js";
9
9
  import { trackAgentTaskCompleted } from "@penclipai/shared/telemetry";
10
10
  import { validate } from "../middleware/validate.js";
@@ -15,7 +15,7 @@ import { conflict, forbidden, HttpError, notFound, unprocessable } from "../erro
15
15
  import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
16
16
  import { assertNoAgentHostWorkspaceCommandMutation, collectIssueWorkspaceCommandPaths, } from "./workspace-command-authz.js";
17
17
  import { shouldWakeAssigneeOnCheckout } from "./issues-checkout-wakeup.js";
18
- import { isInlineAttachmentContentType, normalizeIssueAttachmentMaxBytes, normalizeContentType, SVG_CONTENT_TYPE, } from "../attachment-types.js";
18
+ import { isInlineAttachmentContentType, isAllowedContentType, normalizeIssueAttachmentMaxBytes, normalizeContentType, SVG_CONTENT_TYPE, } from "../attachment-types.js";
19
19
  import { queueIssueAssignmentWakeup } from "../services/issue-assignment-wakeup.js";
20
20
  import { resolveExplicitRequestUiLocale } from "../ui-locale.js";
21
21
  import { assertEnvironmentSelectionForCompany } from "./environment-selection.js";
@@ -60,6 +60,17 @@ function applyCreateIssueStatusDefault(req, res, next) {
60
60
  }
61
61
  next();
62
62
  }
63
+ function buildAttachmentContentPath(attachmentId) {
64
+ return `/api/attachments/${attachmentId}/content`;
65
+ }
66
+ function requiresPaperclipAttachmentMetadata(input, fallback) {
67
+ const type = typeof input.type === "string" ? input.type : fallback?.type ?? null;
68
+ const provider = typeof input.provider === "string" ? input.provider : fallback?.provider ?? null;
69
+ return type === "artifact" && provider === "paperclip";
70
+ }
71
+ const attachmentArtifactMetadataInputSchema = z.object({
72
+ attachmentId: z.string().uuid(),
73
+ }).passthrough();
63
74
  function buildCreateIssueActivityStatusDetails(issue, res) {
64
75
  const statusDefault = res.locals.createIssueStatusDefault;
65
76
  const assignmentWakeSkipped = !issue.assigneeAgentId || issue.status === "backlog";
@@ -737,11 +748,43 @@ export function issueRoutes(db, storage, opts = {}) {
737
748
  }
738
749
  }
739
750
  function withContentPath(attachment) {
751
+ const contentPath = `/api/attachments/${attachment.id}/content`;
740
752
  return {
741
753
  ...attachment,
742
- contentPath: `/api/attachments/${attachment.id}/content`,
754
+ contentPath,
755
+ openPath: contentPath,
756
+ downloadPath: `${contentPath}?download=1`,
743
757
  };
744
758
  }
759
+ function parseAttachmentRangeHeader(raw, contentLength) {
760
+ if (!raw)
761
+ return { kind: "none" };
762
+ if (!Number.isSafeInteger(contentLength) || contentLength <= 0)
763
+ return { kind: "invalid" };
764
+ const prefix = "bytes=";
765
+ if (!raw.toLowerCase().startsWith(prefix))
766
+ return { kind: "invalid" };
767
+ const spec = raw.slice(prefix.length).trim();
768
+ if (!spec || spec.includes(","))
769
+ return { kind: "invalid" };
770
+ const [startRaw, endRaw] = spec.split("-", 2);
771
+ if (endRaw === undefined)
772
+ return { kind: "invalid" };
773
+ if (startRaw === "") {
774
+ const suffixLength = Number.parseInt(endRaw, 10);
775
+ if (!Number.isSafeInteger(suffixLength) || suffixLength <= 0)
776
+ return { kind: "invalid" };
777
+ const start = Math.max(contentLength - suffixLength, 0);
778
+ return { kind: "range", start, end: contentLength - 1 };
779
+ }
780
+ const start = Number.parseInt(startRaw, 10);
781
+ if (!Number.isSafeInteger(start) || start < 0 || start >= contentLength)
782
+ return { kind: "invalid" };
783
+ const end = endRaw === "" ? contentLength - 1 : Number.parseInt(endRaw, 10);
784
+ if (!Number.isSafeInteger(end) || end < start)
785
+ return { kind: "invalid" };
786
+ return { kind: "range", start, end: Math.min(end, contentLength - 1) };
787
+ }
745
788
  function parseBooleanQuery(value) {
746
789
  return value === true || value === "true" || value === "1";
747
790
  }
@@ -800,6 +843,32 @@ export function issueRoutes(db, storage, opts = {}) {
800
843
  annotationCommentId: input.commentId,
801
844
  }, "failed to wake assignee on document annotation comment"));
802
845
  }
846
+ async function canonicalizePaperclipArtifactMetadata(input) {
847
+ const parsed = attachmentArtifactMetadataInputSchema.safeParse(input.metadata);
848
+ if (!parsed.success) {
849
+ throw unprocessable("Invalid attachment artifact metadata", {
850
+ code: "invalid_attachment_artifact_metadata",
851
+ details: parsed.error.issues,
852
+ });
853
+ }
854
+ const attachment = await svc.getAttachmentById(parsed.data.attachmentId);
855
+ if (!attachment || attachment.companyId !== input.issue.companyId || attachment.issueId !== input.issue.id) {
856
+ throw unprocessable("Attachment artifact must reference an attachment on the same issue", {
857
+ code: "invalid_attachment_artifact_metadata",
858
+ attachmentId: parsed.data.attachmentId,
859
+ });
860
+ }
861
+ const contentPath = buildAttachmentContentPath(attachment.id);
862
+ return attachmentArtifactWorkProductMetadataSchema.parse({
863
+ attachmentId: attachment.id,
864
+ contentType: normalizeContentType(attachment.contentType),
865
+ byteSize: attachment.byteSize,
866
+ contentPath,
867
+ openPath: contentPath,
868
+ downloadPath: `${contentPath}?download=1`,
869
+ originalFilename: attachment.originalFilename ?? null,
870
+ });
871
+ }
803
872
  async function assertIssueEnvironmentSelection(companyId, environmentId) {
804
873
  if (environmentId === undefined || environmentId === null)
805
874
  return;
@@ -2531,10 +2600,17 @@ export function issueRoutes(db, storage, opts = {}) {
2531
2600
  return;
2532
2601
  if (!(await assertDeliverableMutationAllowedByRunContext(req, res, issue)))
2533
2602
  return;
2534
- const product = await workProductsSvc.createForIssue(issue.id, issue.companyId, {
2603
+ const createInput = {
2535
2604
  ...req.body,
2536
2605
  projectId: req.body.projectId ?? issue.projectId ?? null,
2537
- });
2606
+ };
2607
+ if (requiresPaperclipAttachmentMetadata(createInput)) {
2608
+ createInput.metadata = await canonicalizePaperclipArtifactMetadata({
2609
+ issue,
2610
+ metadata: req.body.metadata ?? null,
2611
+ });
2612
+ }
2613
+ const product = await workProductsSvc.createForIssue(issue.id, issue.companyId, createInput);
2538
2614
  if (!product) {
2539
2615
  res.status(422).json({ error: "Invalid work product payload" });
2540
2616
  return;
@@ -2576,7 +2652,20 @@ export function issueRoutes(db, storage, opts = {}) {
2576
2652
  return;
2577
2653
  if (!(await assertDeliverableMutationAllowedByRunContext(req, res, issue)))
2578
2654
  return;
2579
- const product = await workProductsSvc.update(id, req.body);
2655
+ const patch = { ...req.body };
2656
+ if (requiresPaperclipAttachmentMetadata(patch, existing)) {
2657
+ if (patch.metadata !== undefined) {
2658
+ patch.metadata = await canonicalizePaperclipArtifactMetadata({
2659
+ issue,
2660
+ metadata: patch.metadata ?? null,
2661
+ });
2662
+ }
2663
+ else if (!requiresPaperclipAttachmentMetadata(existing)) {
2664
+ res.status(422).json({ error: "Attachment-backed artifact metadata is required" });
2665
+ return;
2666
+ }
2667
+ }
2668
+ const product = await workProductsSvc.update(id, patch);
2580
2669
  if (!product) {
2581
2670
  res.status(404).json({ error: "Work product not found" });
2582
2671
  return;
@@ -5161,6 +5250,10 @@ export function issueRoutes(db, storage, opts = {}) {
5161
5250
  res.status(422).json({ error: "Attachment is empty" });
5162
5251
  return;
5163
5252
  }
5253
+ if (!isAllowedContentType(contentType)) {
5254
+ res.status(422).json({ error: `Unsupported attachment content type: ${contentType}` });
5255
+ return;
5256
+ }
5164
5257
  const parsedMeta = createIssueAttachmentMetadataSchema.safeParse(req.body ?? {});
5165
5258
  if (!parsedMeta.success) {
5166
5259
  res.status(400).json({ error: "Invalid attachment metadata", details: parsedMeta.error.issues });
@@ -5212,21 +5305,39 @@ export function issueRoutes(db, storage, opts = {}) {
5212
5305
  return;
5213
5306
  }
5214
5307
  assertCompanyAccess(req, attachment.companyId);
5215
- const object = await storage.getObject(attachment.companyId, attachment.objectKey);
5308
+ const contentLength = attachment.byteSize;
5309
+ const range = parseAttachmentRangeHeader(typeof req.headers.range === "string" ? req.headers.range : undefined, contentLength);
5310
+ res.setHeader("Accept-Ranges", "bytes");
5311
+ if (range.kind === "invalid") {
5312
+ res.setHeader("Content-Range", `bytes */${contentLength}`);
5313
+ res.status(416).end();
5314
+ return;
5315
+ }
5316
+ const object = await storage.getObject(attachment.companyId, attachment.objectKey, range.kind === "range" ? { range: { start: range.start, end: range.end } } : undefined);
5216
5317
  const responseContentType = normalizeContentType(attachment.contentType || object.contentType);
5217
5318
  res.setHeader("Content-Type", responseContentType);
5218
- res.setHeader("Content-Length", String(attachment.byteSize || object.contentLength || 0));
5219
5319
  res.setHeader("Cache-Control", "private, max-age=60");
5220
5320
  res.setHeader("X-Content-Type-Options", "nosniff");
5221
5321
  if (responseContentType === SVG_CONTENT_TYPE) {
5222
5322
  res.setHeader("Content-Security-Policy", "sandbox; default-src 'none'; img-src 'self' data:; style-src 'unsafe-inline'");
5223
5323
  }
5224
5324
  const filename = attachment.originalFilename ?? "attachment";
5225
- const disposition = isInlineAttachmentContentType(responseContentType) ? "inline" : "attachment";
5325
+ const disposition = parseBooleanQuery(req.query.download)
5326
+ ? "attachment"
5327
+ : isInlineAttachmentContentType(responseContentType) ? "inline" : "attachment";
5226
5328
  res.setHeader("Content-Disposition", `${disposition}; filename=\"${filename.replaceAll("\"", "")}\"`);
5227
5329
  object.stream.on("error", (err) => {
5228
5330
  next(err);
5229
5331
  });
5332
+ if (range.kind === "range") {
5333
+ const rangeLength = range.end - range.start + 1;
5334
+ res.status(206);
5335
+ res.setHeader("Content-Length", String(rangeLength));
5336
+ res.setHeader("Content-Range", `bytes ${range.start}-${range.end}/${contentLength}`);
5337
+ object.stream.pipe(res);
5338
+ return;
5339
+ }
5340
+ res.setHeader("Content-Length", String(contentLength || object.contentLength || 0));
5230
5341
  object.stream.pipe(res);
5231
5342
  });
5232
5343
  router.delete("/attachments/:attachmentId", async (req, res) => {