@bud.sh/app 0.4.1 → 0.5.1

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 (74) hide show
  1. package/dist/client/assets/bud/design.js +1 -1
  2. package/dist/client/assets/{canvas-DIKX_HCJ.js → canvas-8GXJIuDK.js} +1 -1
  3. package/dist/client/assets/difference-worker-C99ychYw.js +8 -0
  4. package/dist/client/assets/{edit-B050x0rV.js → edit-DUotSxjS.js} +12 -12
  5. package/dist/client/assets/files-DkWt1l9H.js +1 -0
  6. package/dist/client/assets/i18n-hH_Ba5QO.js +1 -0
  7. package/dist/client/assets/{index-COvyj5zV.js → index-Dn2pfmXf.js} +2 -2
  8. package/dist/client/assets/index-tpHYVXma.css +2 -0
  9. package/dist/client/assets/lru-DzKYIXMA.js +1 -0
  10. package/dist/client/assets/pages-BVd6MQmu.js +1 -0
  11. package/dist/client/assets/{project-branches-DwKjCwZv.js → project-branches-CMGRmrqr.js} +1 -1
  12. package/dist/client/assets/project-comments-D1IIQwsW.js +1 -0
  13. package/dist/client/assets/project-thread-links-DKwe_SYb.js +1 -0
  14. package/dist/client/assets/{project-threads-DeKXNqeP.js → project-threads-ZbKDh78d.js} +105 -105
  15. package/dist/client/assets/{project-work-B7PGQtV9.js → project-work-D4DZqBCZ.js} +1 -1
  16. package/dist/client/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  17. package/dist/client/assets/task-design-BPpc4Gd7.js +23 -0
  18. package/dist/client/assets/tasks-Cn0VOZ9Z.js +1 -0
  19. package/dist/client/assets/{tasks-request-CsUB5__X.js → tasks-request-BLyOzokZ.js} +1 -1
  20. package/dist/client/assets/workspace-DGErsSg6.js +2 -0
  21. package/dist/client/index.html +3 -3
  22. package/dist/hosted/assets/{canvas-gWj_ocKK.js → canvas-BYTOp1p7.js} +6 -4
  23. package/dist/hosted/assets/{comment-data-C-rNCB1n.js → comment-data-Cn5y2VxV.js} +4026 -3665
  24. package/dist/hosted/assets/{files-CAPvbavY.js → files-B1P2_24q.js} +5 -3
  25. package/dist/hosted/assets/{pages-DJiOvT-l.js → pages-B0ZlVdci.js} +3 -3
  26. package/dist/hosted/assets/{project-branches-BgrfdvtL.js → project-branches-DlCWmfRo.js} +1 -1
  27. package/dist/hosted/assets/{project-thread-links-B7uzThL9.js → project-thread-links-BZXQ200n.js} +2 -2
  28. package/dist/hosted/assets/{screen-D4D9nh4V.js → screen-CfdC3NbR.js} +72 -137
  29. package/dist/hosted/assets/{tasks-C7aGLzBw.js → tasks-_yKh2Z6q.js} +12 -5
  30. package/dist/hosted/assets/{tasks-request-CikFdCgP.js → tasks-request-CFPLvLc7.js} +1 -1
  31. package/dist/hosted/hosted.js +164 -16
  32. package/dist/node/assets/{src-BdvZ2mYc.js → src-CerrKjID.js} +57 -1
  33. package/dist/node/design.js +826 -791
  34. package/dist/node/server.js +25 -3
  35. package/dist/node-host/assets/{canvas-kXzp80a5.js → canvas-DxmcFZCh.js} +6 -4
  36. package/dist/node-host/assets/{comment-data-CeuJbJKJ.js → comment-data-yfWEdDQL.js} +4004 -3643
  37. package/dist/node-host/assets/{files-0YIuvKzb.js → files-anHi-apm.js} +5 -3
  38. package/dist/node-host/assets/{pages-DOF22SyG.js → pages-CW4aF6dK.js} +3 -3
  39. package/dist/node-host/assets/{project-branches-BeEwMBIw.js → project-branches-D7rVCxQX.js} +1 -1
  40. package/dist/node-host/assets/{project-thread-links-Bs_MtfBC.js → project-thread-links-m-OLpsD9.js} +2 -2
  41. package/dist/node-host/assets/{screen-DRTAKkn3.js → screen-DapOVrga.js} +72 -137
  42. package/dist/node-host/assets/{tasks-BA_hcbj5.js → tasks-BBK_CybR.js} +12 -5
  43. package/dist/node-host/assets/{tasks-request-Doc9y_20.js → tasks-request-B0aeNocI.js} +1 -1
  44. package/dist/node-host/node-host.js +164 -16
  45. package/dist/server/assets/{canvas-CiN6jNIZ.js → canvas-CkMK4hoN.js} +7 -5
  46. package/dist/server/assets/{comment-data-9SqALQjT.js → comment-data-NLeHG89b.js} +3781 -3631
  47. package/dist/server/assets/{events-6z5v7Uca.js → events-iHpLGr3k.js} +213 -2
  48. package/dist/server/assets/{files-DBVqeLdL.js → files-CRdl489E.js} +6 -4
  49. package/dist/server/assets/{listener-DGWKUc2o.js → listener-BAYn9Q-u.js} +35 -9
  50. package/dist/server/assets/{pages-DJMLr6j9.js → pages-DXVlJlBC.js} +4 -4
  51. package/dist/server/assets/{project-branches-DbKEmiQT.js → project-branches-CwTsf6WQ.js} +2 -2
  52. package/dist/server/assets/{project-thread-links-C0kV_Pcl.js → project-thread-links-lLS_rq7c.js} +3 -3
  53. package/dist/server/assets/{project-work-C0FN3w5Y.js → project-work-CSZlCwH-.js} +3 -3
  54. package/dist/server/assets/{screen-BtvzEiIa.js → screen-B1zH_1O3.js} +73 -138
  55. package/dist/server/assets/{server-CYvuOSBA.js → server-DxK-UB_Z.js} +30 -4
  56. package/dist/server/assets/{services-DK4fqrlF.js → services-BRrgXYlT.js} +105 -9
  57. package/dist/server/assets/{tasks-DX71x8f9.js → tasks-CGdz-uox.js} +14 -7
  58. package/dist/server/assets/{tasks-request-C3jk9Jyu.js → tasks-request-D2NBjCTl.js} +2 -2
  59. package/dist/server/migration.js +3 -3
  60. package/dist/server/runtime.js +3 -3
  61. package/dist/server/server.js +2 -2
  62. package/dist/types/server.d.ts +11 -1
  63. package/package.json +1 -1
  64. package/dist/client/assets/difference-worker-CwQNxTJL.js +0 -8
  65. package/dist/client/assets/files-BQ9O3Z8-.js +0 -1
  66. package/dist/client/assets/i18n-CL0jBP7Y.js +0 -1
  67. package/dist/client/assets/index-CjhJtepP.css +0 -2
  68. package/dist/client/assets/lru-BkhKJhvt.js +0 -1
  69. package/dist/client/assets/pages-BGl2Yuza.js +0 -1
  70. package/dist/client/assets/project-comments-Cdip2Y10.js +0 -1
  71. package/dist/client/assets/project-thread-links-BGIkGQeU.js +0 -1
  72. package/dist/client/assets/task-design-DJp5yho1.js +0 -23
  73. package/dist/client/assets/tasks-BHXj727C.js +0 -1
  74. package/dist/client/assets/workspace-CbO7RsI2.js +0 -2
@@ -3230,6 +3230,49 @@ var MessageSchema = field("message", strict$1({
3230
3230
  function parseMessageAuthor(value) {
3231
3231
  return parseWork(MessageAuthorSchema, value, "author");
3232
3232
  }
3233
+ /** What each deletion refusal tells the person, safe to show. */
3234
+ var messageDeletionRefusals = {
3235
+ missing: "This message no longer exists.",
3236
+ "not-author": "Only its author can delete a message.",
3237
+ "has-replies": "The first message stays while the discussion has replies. Resolve the discussion instead."
3238
+ };
3239
+ /**
3240
+ * Checks that someone may delete a message: only its author may, and a discussion's first message
3241
+ * only while it is the only one, since deleting it removes the whole discussion.
3242
+ * @param messages - The discussion's complete messages, first message first.
3243
+ * @param messageId - The message to delete.
3244
+ * @param authorId - Who asks, as the server derived them.
3245
+ * @returns Why it can't be deleted, or null when it can.
3246
+ */
3247
+ function messageDeletionRefusal(messages, messageId, authorId) {
3248
+ let message = messages.find((candidate) => candidate.id === messageId);
3249
+ if (!message) return "missing";
3250
+ if (message.author.id !== authorId) return "not-author";
3251
+ if (message.id === messages[0].id && messages.length > 1) return "has-replies";
3252
+ return null;
3253
+ }
3254
+ /**
3255
+ * Leaves out deleted messages; replies to a deleted message move up to its parent.
3256
+ * @param messages - The messages, in order.
3257
+ * @param deleted - The IDs of the messages to leave out.
3258
+ * @returns The remaining messages with complete ancestry.
3259
+ */
3260
+ function withoutMessages(messages, deleted) {
3261
+ let gone = new Set(deleted);
3262
+ if (!gone.size) return [...messages];
3263
+ let parents = new Map(messages.map((message) => [message.id, message.parentId]));
3264
+ let visibleParent = (id) => {
3265
+ while (id !== null && gone.has(id)) id = parents.get(id) ?? null;
3266
+ return id;
3267
+ };
3268
+ return messages.filter((message) => !gone.has(message.id)).map((message) => {
3269
+ let parentId = visibleParent(message.parentId);
3270
+ return parentId === message.parentId ? message : {
3271
+ ...message,
3272
+ parentId
3273
+ };
3274
+ });
3275
+ }
3233
3276
  /**
3234
3277
  * Validates a message returned by storage, never a browser write request.
3235
3278
  * @param value - Untrusted data from a request, adapter or response.
@@ -13637,6 +13680,11 @@ var ThreadStatusInputSchema = field("status", strict$1({
13637
13680
  status: ThreadStatusSchema,
13638
13681
  expectedRevision
13639
13682
  }));
13683
+ /** A message deletion against the revision the reader saw; the server checks its author. */
13684
+ var ThreadDeleteInputSchema = field("delete", strict$1({
13685
+ messageId: identifier$1,
13686
+ expectedRevision
13687
+ }));
13640
13688
  /** A revision-checked set of work-item links. */
13641
13689
  var ThreadLinkInputSchema = field("link", verify(strict$1({
13642
13690
  itemIds,
@@ -13721,6 +13769,14 @@ function parseThreadStatusInput(value) {
13721
13769
  return parseWork(ThreadStatusInputSchema, value, "status");
13722
13770
  }
13723
13771
  /**
13772
+ * Validates a message deletion against the revision the reader saw.
13773
+ * @param value - Untrusted data from a request, adapter or response.
13774
+ * @returns The message ID and expected revision.
13775
+ */
13776
+ function parseThreadDeleteInput(value) {
13777
+ return parseWork(ThreadDeleteInputSchema, value, "delete");
13778
+ }
13779
+ /**
13724
13780
  * Validates a revision-checked set of work-item links.
13725
13781
  * @param value - Untrusted data from a request, adapter or response.
13726
13782
  * @returns The linked item IDs and expected revision.
@@ -13788,6 +13844,159 @@ function parseThreadChange(value) {
13788
13844
  return parseWork(ThreadChangeSchema, value, "change");
13789
13845
  }
13790
13846
  //#endregion
13847
+ //#region ../work/src/lib/predict.ts
13848
+ /**
13849
+ * How a new task shows until its adapter confirms it: the requested values, and the creation
13850
+ * time for timestamps the adapter sets, under a provisional identity with no revision,
13851
+ * relations or counts yet.
13852
+ * @param schema - The board's schema.
13853
+ * @param id - A provisional identity no adapter uses.
13854
+ * @param create - The create request.
13855
+ * @param now - The creation time.
13856
+ * @returns The provisional task.
13857
+ */
13858
+ function predictWorkCreate(schema, id, create, now = /* @__PURE__ */ new Date()) {
13859
+ let values = { ...create.values };
13860
+ for (let field of schema.fields) if ((field.role === "created" || field.role === "updated") && values[field.id] === void 0) values[field.id] = field.kind === "date" ? now.toISOString().slice(0, 10) : now.toISOString();
13861
+ return {
13862
+ id,
13863
+ revision: null,
13864
+ values,
13865
+ relations: [],
13866
+ counts: {},
13867
+ contentLoaded: false,
13868
+ extra: null
13869
+ };
13870
+ }
13871
+ /**
13872
+ * How a task shows until its adapter confirms an edit: the edited values over its own.
13873
+ * @param item - The task as last confirmed.
13874
+ * @param update - The update request.
13875
+ * @returns The predicted task.
13876
+ */
13877
+ function predictWorkUpdate(item, update) {
13878
+ return {
13879
+ ...item,
13880
+ values: {
13881
+ ...item.values,
13882
+ ...update.values
13883
+ }
13884
+ };
13885
+ }
13886
+ var targets = {
13887
+ close: ["done", "cancelled"],
13888
+ reopen: [
13889
+ "unstarted",
13890
+ "backlog",
13891
+ "started"
13892
+ ]
13893
+ };
13894
+ /**
13895
+ * How a task shows until its adapter confirms an action. Closing and reopening move it to
13896
+ * the schema's first matching status; otherwise only input naming the task's own fields
13897
+ * applies, since an action's effects belong to the adapter.
13898
+ * @param schema - The board's schema.
13899
+ * @param item - The task as last confirmed.
13900
+ * @param action - The action request.
13901
+ * @returns The predicted task.
13902
+ */
13903
+ function predictWorkAction(schema, item, action) {
13904
+ let fields = new Set(schema.fields.map((field) => field.id));
13905
+ let values = { ...item.values };
13906
+ for (let [id, value] of Object.entries(action.input)) if (fields.has(id)) values[id] = value;
13907
+ let kind = schema.actions.find((candidate) => candidate.id === action.action)?.kind;
13908
+ let categories = kind ? targets[kind] : void 0;
13909
+ let field = schema.fields.find((candidate) => candidate.role === "status");
13910
+ let status = categories?.map((category) => schema.statuses.find((candidate) => candidate.category === category)).find(Boolean);
13911
+ if (field && status) values[field.id] = status.value;
13912
+ return {
13913
+ ...item,
13914
+ values
13915
+ };
13916
+ }
13917
+ /** Who a message shows as until the server, which derives authors from Git, confirms it. */
13918
+ var pendingAuthor = {
13919
+ id: "pending",
13920
+ name: "You",
13921
+ email: ""
13922
+ };
13923
+ function message(id, body, parentId, now) {
13924
+ return {
13925
+ id,
13926
+ body: body.trim(),
13927
+ author: pendingAuthor,
13928
+ createdAt: now.toISOString(),
13929
+ parentId
13930
+ };
13931
+ }
13932
+ /**
13933
+ * How a new discussion shows until its adapter confirms it.
13934
+ * @param id - A provisional identity, also used for its first message.
13935
+ * @param input - The create request.
13936
+ * @param now - The creation time.
13937
+ * @returns The provisional discussion.
13938
+ */
13939
+ function predictThreadCreate(id, input, now = /* @__PURE__ */ new Date()) {
13940
+ let createdAt = now.toISOString();
13941
+ return {
13942
+ id,
13943
+ status: "open",
13944
+ anchor: input.anchor,
13945
+ itemIds: [...input.itemIds],
13946
+ messages: [message(id, input.body, null, now)],
13947
+ messageCount: 1,
13948
+ messagesLoaded: true,
13949
+ messagesTruncated: false,
13950
+ createdAt,
13951
+ updatedAt: createdAt,
13952
+ revision: null
13953
+ };
13954
+ }
13955
+ /**
13956
+ * How a discussion shows until its adapter confirms a reply.
13957
+ * @param thread - The discussion as last confirmed.
13958
+ * @param id - A provisional message identity.
13959
+ * @param input - The reply request.
13960
+ * @param now - The reply time.
13961
+ * @returns The predicted discussion.
13962
+ */
13963
+ function predictThreadReply(thread, id, input, now = /* @__PURE__ */ new Date()) {
13964
+ return {
13965
+ ...thread,
13966
+ messages: thread.messagesLoaded ? [...thread.messages, message(id, input.body, input.parentId, now)] : thread.messages,
13967
+ messageCount: thread.messageCount + 1,
13968
+ updatedAt: now.toISOString()
13969
+ };
13970
+ }
13971
+ /**
13972
+ * How a discussion shows until its adapter confirms a deletion: without the message, or gone
13973
+ * when it was the first.
13974
+ * @param thread - The discussion as last confirmed.
13975
+ * @param messageId - The message being deleted.
13976
+ * @returns The predicted discussion, or null when the whole discussion goes.
13977
+ */
13978
+ function predictThreadDelete(thread, messageId) {
13979
+ if (thread.messages[0]?.id === messageId) return null;
13980
+ let messages = withoutMessages(thread.messages, [messageId]);
13981
+ return {
13982
+ ...thread,
13983
+ messages,
13984
+ messageCount: thread.messageCount - (messages.length < thread.messages.length ? 1 : 0)
13985
+ };
13986
+ }
13987
+ /**
13988
+ * How a discussion shows until its adapter confirms a status change.
13989
+ * @param thread - The discussion as last confirmed.
13990
+ * @param input - The status request.
13991
+ * @returns The predicted discussion.
13992
+ */
13993
+ function predictThreadStatus(thread, input) {
13994
+ return {
13995
+ ...thread,
13996
+ status: input.status
13997
+ };
13998
+ }
13999
+ //#endregion
13791
14000
  //#region ../ui/src/lib/routes.ts
13792
14001
  /** Places in Bud's task screen, shared by links and the screen's matcher. */
13793
14002
  var taskRoutes = route("/tasks", {
@@ -14228,7 +14437,9 @@ var routes = route({
14228
14437
  status: post("/api/comments/:id/status"),
14229
14438
  link: post("/api/comments/:id/links"),
14230
14439
  unlink: post("/api/comments/:id/links/remove"),
14231
- sync: post("/api/comments/sync")
14440
+ deleteMessage: post("/api/comments/:id/messages/remove"),
14441
+ sync: post("/api/comments/sync"),
14442
+ viewer: get("/api/viewer")
14232
14443
  }
14233
14444
  });
14234
14445
  //#endregion
@@ -14262,4 +14473,4 @@ function parseLiveEvent(value) {
14262
14473
  return parse(LiveEventSchema, value);
14263
14474
  }
14264
14475
  //#endregion
14265
- export { parseReviewActionRecovery as $, createWorkItemSchema as $t, parseThreadReplyInput as A, iconNames as An, filterFileEntries as At, resolveRegion as B, isWithinDirectory as Bt, parseAnchor as C, WorkValidationError as Cn, compileSearchPattern as Ct, parseThreadId as D, record$1 as Dn, parseFileSearchQuery as Dt, parseThreadFilter as E, parseWork as En, searchPathMatches as Et, resolveCodeAnchor as F, parseFileChange as Ft, cleanLastNewline as G, list$1 as Gt, diffWordsWithSpace as H, parseFilePath as Ht, parseFileUpdate as I, parseFileDocument as It, getHunkSideStartBoundary as J, strict as Jt, composeCacheKey as K, parseContract as Kt, applyReviewSelection as L, parseFileIndex as Lt, parseThreadStatus as M, FileDocumentSchema as Mt, parseThreadStatusInput as N, FileEntrySchema as Nt, parseThreadInput as O, strict$1 as On, parseFileSearchResult as Ot, createCodeAnchor as P, FileIndexSchema as Pt, parseReviewActionRecoveries as Q, WorkConnectionSchema as Qt, reviewConflictIdentity as R, parseFileIndexQuery as Rt, ThreadSchema as S, statusCategory as Sn, parseReviewSourceQuery as St, parseThreadCapabilities as T, nonempty as Tn, replacementEdits as Tt, diffChars as U, pathHierarchy as Ut, parseDiffFromFile as V, parentPath as Vt, slideBlankBoundaryBlocksUp as W, integer as Wt, parseReviewActionIntent as X, parseElementAnchor as Xt, parseReviewActionApply as Y, MAX_CANVAS_Y as Yt, parseReviewActionPlan as Z, parseWorkWorkspace as Zt, taskRoutes as _, parseMessage as _n, parseReviewHistoryQuery as _t, CommentMergeError as a, parseWorkDetail as an, parseMutationIntent as at, MAX_THREADS as b, fieldByRole as bn, parseReviewSnapshot as bt, parseCommentInput as c, parseWorkMutationResult as cn, parseRecoveries as ct, parseCommentThread as d, parseWorkSnapshot as dn, validateMutationSelection as dt, parseSectionData as en, parseReviewActionResult as et, revision as f, parseWorkSync as fn, ReviewRepositorySchema as ft, pageRoutes as g, valueByRole as gn, parseReviewHistory as gt, fileRoutes as h, parseWorkValue as hn, parseReviewDiffQuery as ht, routes as i, parseWorkCreate as in, parseMutationApply as it, parseThreadSnapshot as j, orderFileEntries as jt, parseThreadLinkInput as k, Icon as kn, classifyText as kt, conversationId as l, parseWorkPatch as ln, parseRecovery as lt, conversationRoutes as m, parseWorkUpdate as mn, parseReviewDiff as mt, parseLiveEvent as n, parseWorkActivity as nn, parseFileSaveResult as nt, mergeThreads as o, parseWorkItem as on, parseMutationPlan as ot, text as p, parseWorkSyncResult as pn, parseReviewComparison as pt, getHunkSideEndBoundary as q, revision$1 as qt, parseLiveId as r, parseWorkConnection as rn, maxFileSaveBytes as rt, stableJson as s, parseWorkItemRef as sn, parseMutationResult as st, RESYNC as t, parseWorkActionInput as tn, parseFileSaveRequest as tt, object$1 as u, parseWorkQuery as un, pathCollisionKey as ut, parseThreadChange as v, parseMessageAuthor as vn, parseReviewRepository as vt, parseThread as w, identifier$1 as wn, matchFileText as wt, ThreadCapabilitiesSchema as x, parseWorkSchema as xn, parseReviewSource as xt, parseWorkChange as y, WorkSchemaSchema as yn, parseReviewRevision as yt, normalizeDiffResolution as z, isProtectedPath as zt };
14476
+ export { cleanLastNewline as $, list$1 as $t, parseAnchor as A, WorkSchemaSchema as An, parseReviewSourceQuery as At, parseThreadStatus as B, Icon as Bn, FileDocumentSchema as Bt, predictWorkCreate as C, parseWorkValue as Cn, parseReviewDiffQuery as Ct, MAX_THREADS as D, parseMessage as Dn, parseReviewRevision as Dt, parseWorkChange as E, messageDeletionRefusals as En, parseReviewRepository as Et, parseThreadId as F, identifier$1 as Fn, parseFileSearchQuery as Ft, applyReviewSelection as G, parseFileIndex as Gt, createCodeAnchor as H, FileIndexSchema as Ht, parseThreadInput as I, nonempty as In, parseFileSearchResult as It, resolveRegion as J, isWithinDirectory as Jt, reviewConflictIdentity as K, parseFileIndexQuery as Kt, parseThreadLinkInput as L, parseWork as Ln, classifyText as Lt, parseThreadCapabilities as M, parseWorkSchema as Mn, matchFileText as Mt, parseThreadDeleteInput as N, statusCategory as Nn, replacementEdits as Nt, ThreadCapabilitiesSchema as O, parseMessageAuthor as On, parseReviewSnapshot as Ot, parseThreadFilter as P, WorkValidationError as Pn, searchPathMatches as Pt, slideBlankBoundaryBlocksUp as Q, integer as Qt, parseThreadReplyInput as R, record$1 as Rn, filterFileEntries as Rt, predictWorkAction as S, parseWorkUpdate as Sn, parseReviewDiff as St, parseThreadChange as T, messageDeletionRefusal as Tn, parseReviewHistoryQuery as Tt, resolveCodeAnchor as U, parseFileChange as Ut, parseThreadStatusInput as V, iconNames as Vn, FileEntrySchema as Vt, parseFileUpdate as W, parseFileDocument as Wt, diffWordsWithSpace as X, parseFilePath as Xt, parseDiffFromFile as Y, parentPath as Yt, diffChars as Z, pathHierarchy as Zt, taskRoutes as _, parseWorkPatch as _n, parseRecovery as _t, CommentMergeError as a, parseWorkWorkspace as an, parseReviewActionPlan as at, predictThreadReply as b, parseWorkSync as bn, ReviewRepositorySchema as bt, parseCommentInput as c, parseSectionData as cn, parseReviewActionResult as ct, parseCommentThread as d, parseWorkConnection as dn, maxFileSaveBytes as dt, parseContract as en, composeCacheKey as et, revision as f, parseWorkCreate as fn, parseMutationApply as ft, pageRoutes as g, parseWorkMutationResult as gn, parseRecoveries as gt, fileRoutes as h, parseWorkItemRef as hn, parseMutationResult as ht, routes as i, parseElementAnchor as in, parseReviewActionIntent as it, parseThread as j, fieldByRole as jn, compileSearchPattern as jt, ThreadSchema as k, withoutMessages as kn, parseReviewSource as kt, conversationId as l, parseWorkActionInput as ln, parseFileSaveRequest as lt, conversationRoutes as m, parseWorkItem as mn, parseMutationPlan as mt, parseLiveEvent as n, strict as nn, getHunkSideStartBoundary as nt, mergeThreads as o, WorkConnectionSchema as on, parseReviewActionRecoveries as ot, text as p, parseWorkDetail as pn, parseMutationIntent as pt, normalizeDiffResolution as q, isProtectedPath as qt, parseLiveId as r, MAX_CANVAS_Y as rn, parseReviewActionApply as rt, stableJson as s, createWorkItemSchema as sn, parseReviewActionRecovery as st, RESYNC as t, revision$1 as tn, getHunkSideEndBoundary as tt, object$1 as u, parseWorkActivity as un, parseFileSaveResult as ut, predictThreadCreate as v, parseWorkQuery as vn, pathCollisionKey as vt, predictWorkUpdate as w, valueByRole as wn, parseReviewHistory as wt, predictThreadStatus as x, parseWorkSyncResult as xn, parseReviewComparison as xt, predictThreadDelete as y, parseWorkSnapshot as yn, validateMutationSelection as yt, parseThreadSnapshot as z, strict$1 as zn, orderFileEntries as zt };
@@ -1,10 +1,10 @@
1
1
  import { C as getFiletypeFromFileName, P as __toESM, S as getCustomExtensionsVersion, x as getCustomExtensionsMap } from "./cloneFileDiffMetadata-B-xwytg8.js";
2
- import { Dt as parseFileSearchQuery, Ft as parseFileChange, Ht as parseFilePath, I as parseFileUpdate, It as parseFileDocument, Lt as parseFileIndex, Ot as parseFileSearchResult, P as createCodeAnchor, Q as parseReviewActionRecoveries, R as reviewConflictIdentity, Z as parseReviewActionPlan, bt as parseReviewSnapshot, ct as parseRecoveries, et as parseReviewActionResult, gt as parseReviewHistory, h as fileRoutes, i as routes, mt as parseReviewDiff, nt as parseFileSaveResult, ot as parseMutationPlan, rt as maxFileSaveBytes, st as parseMutationResult, tt as parseFileSaveRequest, vt as parseReviewRepository, xt as parseReviewSource } from "./events-6z5v7Uca.js";
3
- import { $t as areFileRenderOptionsEqual, A as FileRecoveryDialog, At as fileHref, Ct as readReviewLocation, D as FileEditorPanel, Dt as reviewHref, E as ReviewActionDialog, En as t, Et as reviewContextKey, F as defaultFileDestination, G as ConversationSidebar, Gt as areDiffTargetsEqual, Ht as renderDiffWithHighlighter, I as fileActionIntent, Jt as WorkerPoolWorkerError, Kt as WorkerPoolTaskCanceledError, L as mutationFileView, M as FileReviewPanel, Mt as readFileLocation, N as codeThemes, Nt as reconcileFileView, O as defaultEditorPreferences, On as Text, Ot as closeFileTab, P as FileWorkspace, Pt as rememberFile, Qt as renderFileWithHighlighter, R as remainingMutationIntent, Sn as writePreference, St as parseReviewSession, T as FileConflictPanel, Tt as reviewComparison, U as FileSearchPanel, Ut as areDiffRenderOptionsEqual, Vt as isDiffPlainText, Wt as areFilesEqual, Xt as markWorkerErrorReported, Yt as isHandledWorkerPoolError, Zt as isFilePlainText, an as attachResolvedThemes, bn as toast, bt as defaultReviewView, cn as getResolvedOrResolveLanguage, ct as codeCommentCounts, dn as ResolvedLanguages, en as hasResolvedThemes, f as storeDocument, ft as isCodeConversation, ht as readConversationLocation, in as validateResolvedThemeName, j as FileMutationDialog, jt as parseFileView, k as parseEditorPreferences, kt as defaultFileView, l as projectStore, ln as resolveLanguage, m as storedFiles, mt as locateCodeConversations, nn as getSharedHighlighter, on as themeResolver, p as storedDocument, qt as WorkerPoolTerminatedError, rn as prepareThemeResolution, s as applyFileUpdate, sn as getThemes, tn as areThemesEqual, u as saveFiles, un as areLanguagesAttached, ut as conversationHref, v as projectLive, wt as rememberReviewPosition, xn as readPreference, yt as defaultReviewPosition } from "./comment-data-9SqALQjT.js";
2
+ import { Et as parseReviewRepository, Ft as parseFileSearchQuery, Gt as parseFileIndex, H as createCodeAnchor, It as parseFileSearchResult, K as reviewConflictIdentity, Ot as parseReviewSnapshot, St as parseReviewDiff, Ut as parseFileChange, W as parseFileUpdate, Wt as parseFileDocument, Xt as parseFilePath, at as parseReviewActionPlan, ct as parseReviewActionResult, dt as maxFileSaveBytes, gt as parseRecoveries, h as fileRoutes, ht as parseMutationResult, i as routes, kt as parseReviewSource, lt as parseFileSaveRequest, mt as parseMutationPlan, ot as parseReviewActionRecoveries, ut as parseFileSaveResult, wt as parseReviewHistory } from "./events-iHpLGr3k.js";
3
+ import { $t as areFileRenderOptionsEqual, A as FileRecoveryDialog, At as fileHref, Ct as readReviewLocation, D as FileEditorPanel, Dt as reviewHref, E as ReviewActionDialog, En as t, Et as reviewContextKey, F as defaultFileDestination, G as ConversationSidebar, Gt as areDiffTargetsEqual, Ht as renderDiffWithHighlighter, I as fileActionIntent, Jt as WorkerPoolWorkerError, Kt as WorkerPoolTaskCanceledError, L as mutationFileView, M as FileReviewPanel, Mt as readFileLocation, N as codeThemes, Nt as reconcileFileView, O as defaultEditorPreferences, On as Text, Ot as closeFileTab, P as FileWorkspace, Pt as rememberFile, Qt as renderFileWithHighlighter, R as remainingMutationIntent, Sn as writePreference, St as parseReviewSession, T as FileConflictPanel, Tt as reviewComparison, U as FileSearchPanel, Ut as areDiffRenderOptionsEqual, Vt as isDiffPlainText, Wt as areFilesEqual, Xt as markWorkerErrorReported, Yt as isHandledWorkerPoolError, Zt as isFilePlainText, an as attachResolvedThemes, bn as toast, bt as defaultReviewView, cn as getResolvedOrResolveLanguage, ct as codeCommentCounts, dn as ResolvedLanguages, en as hasResolvedThemes, f as storeDocument, ft as isCodeConversation, ht as readConversationLocation, in as validateResolvedThemeName, j as FileMutationDialog, jt as parseFileView, k as parseEditorPreferences, kt as defaultFileView, l as projectStore, ln as resolveLanguage, m as storedFiles, mt as locateCodeConversations, nn as getSharedHighlighter, on as themeResolver, p as storedDocument, qt as WorkerPoolTerminatedError, rn as prepareThemeResolution, s as applyFileUpdate, sn as getThemes, tn as areThemesEqual, u as saveFiles, un as areLanguagesAttached, ut as conversationHref, v as projectLive, wt as rememberReviewPosition, xn as readPreference, yt as defaultReviewPosition } from "./comment-data-NLeHG89b.js";
4
4
  import { l as DEFAULT_THEMES } from "./constants-C7Y3SJGj.js";
5
- import { n as createProjectComments, t as defineScreen } from "./screen-BtvzEiIa.js";
6
5
  import { t as require_lru } from "./lru-C4Rh6JYD.js";
7
- import { t as ProjectThreadLinks } from "./project-thread-links-C0kV_Pcl.js";
6
+ import { n as createProjectComments, t as defineScreen } from "./screen-B1zH_1O3.js";
7
+ import { t as ProjectThreadLinks } from "./project-thread-links-lLS_rq7c.js";
8
8
  import { ref } from "remix/component";
9
9
  import { jsx, jsxs } from "remix/component/jsx-runtime";
10
10
  //#region ../../node_modules/.pnpm/@pierre+diffs@1.5.2_@shikijs+themes@4.5.0_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@pierre/diffs/dist/highlighter/languages/getResolvedLanguages.js
@@ -3272,6 +3272,8 @@ function ProjectFileReview(handle) {
3272
3272
  },
3273
3273
  onClose: closeComments,
3274
3274
  onWrite: comments.write,
3275
+ viewerId: comments.viewer?.id,
3276
+ onDelete: (thread, messageId) => comments.remove(thread.id, messageId),
3275
3277
  onCreate: createComment,
3276
3278
  onCancelDraft: () => {
3277
3279
  draftAnchor = void 0;
@@ -1,9 +1,9 @@
1
- import { Dn as tryPromise, Dt as callback, Ft as fail$1, Gt as map, Kt as mapError, Lt as flatMap, Mn as void_, Nt as die, On as try_, Pt as ensuring, Sn as sync, St as andThen, Ut as gen, Zt as promise, g as resolveScreenRoutes, gn as scoped, gr as TaggedError, h as defaultScreens, qt as match, s as Previews, t as BranchPreviews, u as Git, v as themeStyle, vt as acquireRelease, y as LOGO_TYPES } from "./branch-previews-ClkoJ0lM.js";
2
- import { C as selected$1, I as WorkError, L as ScreenModules, O as AdapterRegistry, S as ready, T as LiveChannel, V as taskDesignModuleId, a as FileMutations, b as read, c as FileReview, f as Files, g as StoreActivity, h as ReviewActionError, m as FilesInputError, r as FileSaves, t as FileReviewActions, u as FileSearch, w as validate, x as readWorkspace, y as inspect } from "./server-CYvuOSBA.js";
3
- import { A as parseThreadReplyInput, D as parseThreadId, Dt as parseFileSearchQuery, E as parseThreadFilter, Ht as parseFilePath, N as parseThreadStatusInput, O as parseThreadInput, Rt as parseFileIndexQuery, St as parseReviewSourceQuery, X as parseReviewActionIntent, Xt as parseElementAnchor, Y as parseReviewActionApply, Yt as MAX_CANVAS_Y, _ as taskRoutes, _t as parseReviewHistoryQuery, an as parseWorkDetail, at as parseMutationIntent, cn as parseWorkMutationResult, en as parseSectionData, fn as parseWorkSync, g as pageRoutes, h as fileRoutes, ht as parseReviewDiffQuery, i as routes, in as parseWorkCreate, it as parseMutationApply, j as parseThreadSnapshot, k as parseThreadLinkInput, mn as parseWorkUpdate, pn as parseWorkSyncResult, pt as parseReviewComparison, rt as maxFileSaveBytes, sn as parseWorkItemRef, tn as parseWorkActionInput, tt as parseFileSaveRequest, un as parseWorkQuery, vn as parseMessageAuthor, w as parseThread } from "./events-6z5v7Uca.js";
4
- import { $ as openShellTab, B as parseTaskDesign, Bt as Button, Cn as hasMessage, Dn as useLocaleSource, En as t, J as FieldCardContent, On as Text, Q as initialShellTabs, Rt as Loader, Sn as writePreference, Tn as locale, X as activeTab, Y as FieldCardHeader, Z as closeShellTab, _ as requestComments, _n as LiveStatus, _t as taskHref, at as tabsCookieValue, et as parseShellTabs, gt as selectedTask, ht as readConversationLocation, it as tabsCookieName, lt as conversationDestination, mn as ShellTabBar, n as unavailableComments, nt as stepShellTab, ot as visitShellTab, pt as legacyConversationHref, q as FieldCard, r as followThreads, rt as tabHref, t as commentsUnavailable, tt as readTabsCookie, v as projectLive, wn as isLocale, xn as readPreference, xt as legacyFileHref, yn as AppShell } from "./comment-data-9SqALQjT.js";
1
+ import { Dn as tryPromise, Dt as callback, Ft as fail$1, Gt as map, Kt as mapError, Lt as flatMap, Mn as void_, Nt as die, On as try_, Pt as ensuring, Sn as sync, St as andThen, Ut as gen, Xt as orElseSucceed, Zt as promise, g as resolveScreenRoutes, gn as scoped, gr as TaggedError, h as defaultScreens, qt as match, s as Previews, t as BranchPreviews, u as Git, v as themeStyle, vt as acquireRelease, y as LOGO_TYPES } from "./branch-previews-ClkoJ0lM.js";
2
+ import { C as selected$1, I as WorkError, L as ScreenModules, O as AdapterRegistry, S as ready, T as LiveChannel, V as taskDesignModuleId, a as FileMutations, b as read, c as FileReview, f as Files, g as StoreActivity, h as ReviewActionError, m as FilesInputError, r as FileSaves, t as FileReviewActions, u as FileSearch, w as validate, x as readWorkspace, y as inspect } from "./server-DxK-UB_Z.js";
3
+ import { At as parseReviewSourceQuery, Ct as parseReviewDiffQuery, F as parseThreadId, Ft as parseFileSearchQuery, I as parseThreadInput, Kt as parseFileIndexQuery, L as parseThreadLinkInput, N as parseThreadDeleteInput, On as parseMessageAuthor, P as parseThreadFilter, R as parseThreadReplyInput, Sn as parseWorkUpdate, Tt as parseReviewHistoryQuery, V as parseThreadStatusInput, Xt as parseFilePath, _ as taskRoutes, bn as parseWorkSync, cn as parseSectionData, dt as maxFileSaveBytes, fn as parseWorkCreate, ft as parseMutationApply, g as pageRoutes, gn as parseWorkMutationResult, h as fileRoutes, hn as parseWorkItemRef, i as routes, in as parseElementAnchor, it as parseReviewActionIntent, j as parseThread, ln as parseWorkActionInput, lt as parseFileSaveRequest, pn as parseWorkDetail, pt as parseMutationIntent, rn as MAX_CANVAS_Y, rt as parseReviewActionApply, vn as parseWorkQuery, xn as parseWorkSyncResult, xt as parseReviewComparison, z as parseThreadSnapshot } from "./events-iHpLGr3k.js";
4
+ import { $ as openShellTab, B as parseTaskDesign, Bt as Button, Cn as hasMessage, Dn as useLocaleSource, En as t, J as FieldCardContent, On as Text, Q as initialShellTabs, Rt as Loader, Sn as writePreference, Tn as locale, X as activeTab, Y as FieldCardHeader, Z as closeShellTab, _ as requestComments, _n as LiveStatus, _t as taskHref, at as tabsCookieValue, et as parseShellTabs, gt as selectedTask, ht as readConversationLocation, it as tabsCookieName, lt as conversationDestination, mn as ShellTabBar, n as unavailableComments, nt as stepShellTab, ot as visitShellTab, pt as legacyConversationHref, q as FieldCard, r as followThreads, rt as tabHref, t as commentsUnavailable, tt as readTabsCookie, v as projectLive, wn as isLocale, xn as readPreference, xt as legacyFileHref, yn as AppShell } from "./comment-data-NLeHG89b.js";
5
5
  import { d as parsePreviewHash, f as parsePreviewId, l as parsePreviewBranch, m as parsePreviewViewport } from "./parsers-CsiSkwTT.js";
6
- import { t as projectWork } from "./project-work-C0FN3w5Y.js";
6
+ import { t as projectWork } from "./project-work-CSZlCwH-.js";
7
7
  import { n as showWorkspaceTab } from "./workspace-tab-DAUjkJzZ.js";
8
8
  import { createHash } from "node:crypto";
9
9
  import { extname, isAbsolute, relative, resolve } from "node:path";
@@ -86,10 +86,10 @@ function ProjectLiveStatus(handle) {
86
86
  //#endregion
87
87
  //#region app/client/screens.ts
88
88
  var builtIns = {
89
- "bud:pages": () => import("./pages-DJMLr6j9.js"),
90
- "bud:canvas": () => import("./canvas-CiN6jNIZ.js"),
91
- "bud:tasks": () => import("./tasks-DX71x8f9.js"),
92
- "bud:files": () => import("./files-DBVqeLdL.js")
89
+ "bud:pages": () => import("./pages-DXVlJlBC.js"),
90
+ "bud:canvas": () => import("./canvas-CkMK4hoN.js"),
91
+ "bud:tasks": () => import("./tasks-CGdz-uox.js"),
92
+ "bud:files": () => import("./files-CRdl489E.js")
93
93
  };
94
94
  /**
95
95
  * Imports a screen module: a built-in by its key, any other by the URL the server gave it.
@@ -1114,6 +1114,32 @@ function createCommentsController(project, runtime) {
1114
1114
  unlink({ request, params }) {
1115
1115
  return respond(request, (project) => written(link(request, project, params.id, true)));
1116
1116
  },
1117
+ deleteMessage({ request, params }) {
1118
+ return respond(request, (project) => written(gen(function* () {
1119
+ let id = yield* input$2(() => parseThreadId(params.id));
1120
+ let value = yield* readProjectJsonBody(request, { maxBytes: 64e3 });
1121
+ let parsed = yield* input$2(() => parseThreadDeleteInput(value));
1122
+ let store = yield* writable(project.root, "delete");
1123
+ if (!store.deleteMessage) return yield* new WorkError({
1124
+ reason: "refused",
1125
+ message: "This comment adapter does not support deleting messages."
1126
+ });
1127
+ let author = yield* commentAuthor(project.root);
1128
+ let thread = yield* store.deleteMessage(project.root, id, parsed, author);
1129
+ return yield* result(() => {
1130
+ if (thread === null) return { thread: null };
1131
+ let parsed = parseThread(thread);
1132
+ if (parsed.id !== id) throw new Error("Unexpected discussion identity.");
1133
+ return { thread: parsed };
1134
+ }, true);
1135
+ })));
1136
+ },
1137
+ viewer({ request }) {
1138
+ return respond(request, (project) => commentAuthor(project.root).pipe(map((author) => ({ viewer: {
1139
+ id: author.id,
1140
+ name: author.name
1141
+ } })), orElseSucceed(() => ({ viewer: null }))));
1142
+ },
1117
1143
  sync({ request }) {
1118
1144
  return respond(request, (project) => gen(function* () {
1119
1145
  let value = yield* readProjectJsonBody(request, { maxBytes: 64e3 });
@@ -1,8 +1,8 @@
1
- import { Yt as MAX_CANVAS_Y, g as pageRoutes } from "./events-6z5v7Uca.js";
2
- import { En as t, On as Text, Rt as Loader, Sn as writePreference, gn as IconButton, hn as Select, l as projectStore, st as PagesWorkspace, xn as readPreference, zt as Spinner } from "./comment-data-9SqALQjT.js";
3
- import { n as createProjectComments, t as defineScreen } from "./screen-BtvzEiIa.js";
1
+ import { g as pageRoutes, rn as MAX_CANVAS_Y } from "./events-iHpLGr3k.js";
2
+ import { En as t, On as Text, Rt as Loader, Sn as writePreference, gn as IconButton, hn as Select, l as projectStore, st as PagesWorkspace, xn as readPreference, zt as Spinner } from "./comment-data-NLeHG89b.js";
4
3
  import { r as workspaceTab, t as followWorkspaceTab } from "./workspace-tab-DAUjkJzZ.js";
5
- import { n as createProjectPreviews, r as locatePreview, t as createProjectBranches } from "./project-branches-DbKEmiQT.js";
4
+ import { n as createProjectPreviews, r as locatePreview, t as createProjectBranches } from "./project-branches-CwTsf6WQ.js";
5
+ import { n as createProjectComments, t as defineScreen } from "./screen-B1zH_1O3.js";
6
6
  import { array, number, object, optional, parseSafe, string } from "remix/data-schema";
7
7
  import { on, ref } from "remix/component";
8
8
  import { Fragment, jsx, jsxs } from "remix/component/jsx-runtime";
@@ -1,5 +1,5 @@
1
- import { Xt as parseElementAnchor, i as routes } from "./events-6z5v7Uca.js";
2
- import { En as t, c as previewKey, l as projectStore, v as projectLive, x as writeRows, y as plainRow } from "./comment-data-9SqALQjT.js";
1
+ import { i as routes, in as parseElementAnchor } from "./events-iHpLGr3k.js";
2
+ import { En as t, c as previewKey, l as projectStore, v as projectLive, x as writeRows, y as plainRow } from "./comment-data-NLeHG89b.js";
3
3
  import { c as parsePreview, l as parsePreviewBranch, p as parsePreviewPins } from "./parsers-CsiSkwTT.js";
4
4
  import { array, boolean, enum_, nullable, number, object, parseSafe, string } from "remix/data-schema";
5
5
  //#region app/client/project-previews.ts
@@ -1,6 +1,6 @@
1
- import { Zt as parseWorkWorkspace, gn as valueByRole, i as routes, k as parseThreadLinkInput, sn as parseWorkItemRef, w as parseThread } from "./events-6z5v7Uca.js";
2
- import { C as ThreadTaskPicker, En as t, S as ThreadTaskLinks, _ as requestComments, _t as taskHref, gn as IconButton } from "./comment-data-9SqALQjT.js";
3
- import { n as requestTasks } from "./tasks-request-C3jk9Jyu.js";
1
+ import { L as parseThreadLinkInput, an as parseWorkWorkspace, hn as parseWorkItemRef, i as routes, j as parseThread, wn as valueByRole } from "./events-iHpLGr3k.js";
2
+ import { C as ThreadTaskPicker, En as t, S as ThreadTaskLinks, _ as requestComments, _t as taskHref, gn as IconButton } from "./comment-data-NLeHG89b.js";
3
+ import { n as requestTasks } from "./tasks-request-D2NBjCTl.js";
4
4
  import { on, ref } from "remix/component";
5
5
  import { Fragment, jsx, jsxs } from "remix/component/jsx-runtime";
6
6
  //#region app/client/project-task-picker.tsx
@@ -1,6 +1,6 @@
1
- import { Zt as parseWorkWorkspace, i as routes, y as parseWorkChange } from "./events-6z5v7Uca.js";
2
- import { d as saveWorkspace, l as projectStore, v as projectLive, x as writeRows, y as plainRow } from "./comment-data-9SqALQjT.js";
3
- import { n as requestTasks } from "./tasks-request-C3jk9Jyu.js";
1
+ import { E as parseWorkChange, an as parseWorkWorkspace, i as routes } from "./events-iHpLGr3k.js";
2
+ import { d as saveWorkspace, l as projectStore, v as projectLive, x as writeRows, y as plainRow } from "./comment-data-NLeHG89b.js";
3
+ import { n as requestTasks } from "./tasks-request-D2NBjCTl.js";
4
4
  //#region app/client/project-work.ts
5
5
  var syncs = /* @__PURE__ */ new Map();
6
6
  /**