@maudecode/kanvil 0.5.1 → 0.7.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.
- package/apps/server/dist/{auth-Bm6cIseE.mjs → auth-D43XyHdK.mjs} +266 -68
- package/apps/server/dist/client.mjs +2 -2
- package/apps/server/dist/{config-CrJuk5mY.mjs → config-CQVdVhXv.mjs} +1 -1
- package/apps/server/dist/index.mjs +167 -45
- package/apps/server/dist/migrate.mjs +1 -1
- package/apps/server/dist/recover.mjs +3 -3
- package/apps/server/dist/{src-D80LNZKP.mjs → src-D70GmZ5R.mjs} +170 -28
- package/apps/server/drizzle/0039_intake_credential.sql +2 -0
- package/apps/server/drizzle/0040_upload_urls.sql +20 -0
- package/apps/server/drizzle/0041_project_repositories.sql +2 -0
- package/apps/server/drizzle/meta/0039_snapshot.json +7020 -0
- package/apps/server/drizzle/meta/0040_snapshot.json +7170 -0
- package/apps/server/drizzle/meta/0041_snapshot.json +7183 -0
- package/apps/server/drizzle/meta/_journal.json +21 -0
- package/apps/web/dist/assets/{CompositeItem-Tueq2VKR.js → CompositeItem-DLTRsada.js} +1 -1
- package/apps/web/dist/assets/{Trans-BgU0eWAX.js → Trans-DqX-qhvQ.js} +1 -1
- package/apps/web/dist/assets/admin-settings-BQzdZII5.js +1 -0
- package/apps/web/dist/assets/{archive-restore-CSpoH6mS.js → archive-restore-BO1qng5Y.js} +1 -1
- package/apps/web/dist/assets/az-AZ-SXqDBPA2.js +1 -0
- package/apps/web/dist/assets/{az-DUcDY8Bp.js → az-CEW7-a7J.js} +1 -1
- package/apps/web/dist/assets/configuration-D0zvwrXt.js +1 -0
- package/apps/web/dist/assets/{corner-left-up-C3OGlXIB.js → corner-left-up-Be7Z9Uhf.js} +1 -1
- package/apps/web/dist/assets/{de-89C1V8Ut.js → de-B-oGVMYL.js} +1 -1
- package/apps/web/dist/assets/de-DE-CB7aQ6b-.js +1 -0
- package/apps/web/dist/assets/default-CCI1vZxa.js +56 -0
- package/apps/web/dist/assets/delivery-settings-BrwSrFIN.js +1 -0
- package/apps/web/dist/assets/{el-D6CICkhi.js → el-Cp69kezM.js} +1 -1
- package/apps/web/dist/assets/el-GR-D1ntYXIt.js +1 -0
- package/apps/web/dist/assets/{ellipsis-lJJU8zB7.js → ellipsis-B0AE8ax3.js} +1 -1
- package/apps/web/dist/assets/{es-B20Izib2.js → es-CwOMVSTx.js} +1 -1
- package/apps/web/dist/assets/es-ES-CllsaxcB.js +1 -0
- package/apps/web/dist/assets/{forms--87R7VQW.js → forms-CkVpTx29.js} +1 -1
- package/apps/web/dist/assets/{fr-DVlGnGsu.js → fr-Cy4co9ic.js} +1 -1
- package/apps/web/dist/assets/fr-FR-DxTw6LgI.js +1 -0
- package/apps/web/dist/assets/{hi-D1F5Pi_I.js → hi-DbO9TKwg.js} +1 -1
- package/apps/web/dist/assets/hi-IN-CaQga-0l.js +1 -0
- package/apps/web/dist/assets/{highlight-ygDJPvRy.js → highlight-zMg1BK-r.js} +1 -1
- package/apps/web/dist/assets/{id-LESXKW7G.js → id-B6NKsmCm.js} +1 -1
- package/apps/web/dist/assets/id-ID-DBfwAAqU.js +1 -0
- package/apps/web/dist/assets/index-CZuFd4LM.js +17 -0
- package/apps/web/dist/assets/index-DPT5LAs1.css +2 -0
- package/apps/web/dist/assets/invitations-Dp40BfHj.js +1 -0
- package/apps/web/dist/assets/it-IT-BckuH9Nl.js +1 -0
- package/apps/web/dist/assets/{it-CgRGAs6u.js → it-ilGYCq2T.js} +1 -1
- package/apps/web/dist/assets/item-DQR89bKm.js +1 -0
- package/apps/web/dist/assets/{ja-B7arhzgX.js → ja-D-hJRTgP.js} +1 -1
- package/apps/web/dist/assets/ja-JP-BAGgJKZ4.js +1 -0
- package/apps/web/dist/assets/ko-KR-srIEsTP5.js +1 -0
- package/apps/web/dist/assets/{ko-Ro_UonyA.js → ko-ajkkoJ_d.js} +1 -1
- package/apps/web/dist/assets/label-settings-ChnKkA97.js +1 -0
- package/apps/web/dist/assets/{markdown-blocks-toSPlHSc.js → markdown-blocks-CpzrwyQG.js} +1 -1
- package/apps/web/dist/assets/member-directory-XK0ZEGUq.js +1 -0
- package/apps/web/dist/assets/{mk-DR3kmrIp.js → mk-C_sMyEHX.js} +1 -1
- package/apps/web/dist/assets/mk-MK-BTa1NMAF.js +1 -0
- package/apps/web/dist/assets/{nl-D3uRJJLT.js → nl-D9-P4UPR.js} +1 -1
- package/apps/web/dist/assets/nl-NL-CQduhDqs.js +1 -0
- package/apps/web/dist/assets/{pl-CtzDOLdV.js → pl-CiQM7fSB.js} +1 -1
- package/apps/web/dist/assets/pl-PL-BdZMf7Ni.js +1 -0
- package/apps/web/dist/assets/project-lifecycle-VYecJuiP.js +1 -0
- package/apps/web/dist/assets/project-settings-Bs6YEpo9.js +1 -0
- package/apps/web/dist/assets/{pt-BR-FarXHHuf.js → pt-BR-CP7dhuqF.js} +1 -1
- package/apps/web/dist/assets/pt-BR-DZEXJNHg.js +1 -0
- package/apps/web/dist/assets/public-project-DUfWDao9.js +1 -0
- package/apps/web/dist/assets/{rotate-ccw-Byx7O3RH.js → rotate-ccw-Cxh9ec2s.js} +1 -1
- package/apps/web/dist/assets/{ru-DHMEVxvB.js → ru-DxJ6vF4E.js} +1 -1
- package/apps/web/dist/assets/ru-RU-CZKEe7P8.js +1 -0
- package/apps/web/dist/assets/search-DfbsqO7M.js +85 -0
- package/apps/web/dist/assets/{send-DlGV2XQS.js → send-DrJl0BKm.js} +1 -1
- package/apps/web/dist/assets/settings-BN8uIiBG.js +1 -0
- package/apps/web/dist/assets/{sliders-horizontal-CEHGGft_.js → sliders-horizontal-DM47MLe7.js} +1 -1
- package/apps/web/dist/assets/switch-CJTVGtE9.js +1 -0
- package/apps/web/dist/assets/{table-2AEfwytk.js → table-BLLjFPWD.js} +1 -1
- package/apps/web/dist/assets/ticket-detail-BTy_3JeU.js +2 -0
- package/apps/web/dist/assets/ticket-editor-Bb_lyxnJ.js +2 -0
- package/apps/web/dist/assets/ticket-list-Botp5qf5.js +6 -0
- package/apps/web/dist/assets/ticket-list-controls-Dmkno4pm.js +1 -0
- package/apps/web/dist/assets/{tr-CjdSDu0z.js → tr-9IkdRLIk.js} +1 -1
- package/apps/web/dist/assets/tr-TR-Y8wBLO8I.js +1 -0
- package/apps/web/dist/assets/{uk-C8od6u_H.js → uk-Btampsdw.js} +1 -1
- package/apps/web/dist/assets/uk-UA-CVpasGUS.js +1 -0
- package/apps/web/dist/assets/{upload-BeTAGU_W.js → upload-HARy4VC_.js} +1 -1
- package/apps/web/dist/assets/{useQueries-BtRgTciJ.js → useQueries-CTeEF--U.js} +1 -1
- package/apps/web/dist/assets/{vi-BwdBtgfS.js → vi-BVZzOn_n.js} +1 -1
- package/apps/web/dist/assets/vi-VN-BMy-iJD-.js +1 -0
- package/apps/web/dist/assets/visual-editor-DKBPjqV-.js +208 -0
- package/apps/web/dist/assets/workspace-settings-DqzBNw60.js +1 -0
- package/apps/web/dist/assets/{zh-CN-DM-UoFmL.js → zh-CN-BoUvF2do.js} +1 -1
- package/apps/web/dist/assets/zh-CN-Cds_v0R8.js +1 -0
- package/apps/web/dist/assets/{zh-TW-q2nrwFjt.js → zh-TW-CEIDGTWe.js} +1 -1
- package/apps/web/dist/assets/zh-TW-DCCYakXz.js +1 -0
- package/apps/web/dist/index.html +9 -9
- package/docs/api.md +35 -5
- package/docs/cli.md +1 -1
- package/docs/mobile.md +67 -4
- package/docs/releasing.md +6 -4
- package/package.json +1 -1
- package/apps/web/dist/assets/admin-settings-Ckis3XJG.js +0 -1
- package/apps/web/dist/assets/az-AZ-bFxpMMZN.js +0 -1
- package/apps/web/dist/assets/de-DE-BeXI30Ll.js +0 -1
- package/apps/web/dist/assets/default-Dnep8Yat.js +0 -56
- package/apps/web/dist/assets/delivery-settings-cMldZ9K7.js +0 -1
- package/apps/web/dist/assets/el-GR-SgRHlWhY.js +0 -1
- package/apps/web/dist/assets/es-ES-BF1J5vap.js +0 -1
- package/apps/web/dist/assets/fr-FR-D_sldwf6.js +0 -1
- package/apps/web/dist/assets/hi-IN-CfOw4TWf.js +0 -1
- package/apps/web/dist/assets/id-ID-CLKtHO7Q.js +0 -1
- package/apps/web/dist/assets/index-Bn-MADyj.css +0 -2
- package/apps/web/dist/assets/index-Ds3IHeIi.js +0 -17
- package/apps/web/dist/assets/invitations-C5WbdDUQ.js +0 -1
- package/apps/web/dist/assets/it-IT-eVZNW5qX.js +0 -1
- package/apps/web/dist/assets/item-BD1Poxfs.js +0 -1
- package/apps/web/dist/assets/ja-JP-D96njn-P.js +0 -1
- package/apps/web/dist/assets/ko-KR-Bash_ieA.js +0 -1
- package/apps/web/dist/assets/label-settings-BaikCfal.js +0 -1
- package/apps/web/dist/assets/member-directory-BjUy1KuK.js +0 -1
- package/apps/web/dist/assets/mk-MK-BWQWGIRx.js +0 -1
- package/apps/web/dist/assets/nl-NL-D1tvo0Gd.js +0 -1
- package/apps/web/dist/assets/pl-PL-DNgGUEcQ.js +0 -1
- package/apps/web/dist/assets/project-lifecycle-BBHcRi6p.js +0 -1
- package/apps/web/dist/assets/project-settings-BaYuxYjg.js +0 -1
- package/apps/web/dist/assets/pt-BR-CZsUZQ6P.js +0 -1
- package/apps/web/dist/assets/public-project-DGf3nkg2.js +0 -1
- package/apps/web/dist/assets/ru-RU-4ew92YE_.js +0 -1
- package/apps/web/dist/assets/search-DwsPEC4E.js +0 -85
- package/apps/web/dist/assets/settings-C_sN8Y1h.js +0 -1
- package/apps/web/dist/assets/switch-B_rsZYBf.js +0 -1
- package/apps/web/dist/assets/ticket-detail-C2l8nwF-.js +0 -2
- package/apps/web/dist/assets/ticket-editor-B0UB98HS.js +0 -2
- package/apps/web/dist/assets/ticket-list-D_MHudj1.js +0 -6
- package/apps/web/dist/assets/ticket-list-controls-jKg4i-NA.js +0 -1
- package/apps/web/dist/assets/tr-TR-CM381XCw.js +0 -1
- package/apps/web/dist/assets/uk-UA-AeOiWCVo.js +0 -1
- package/apps/web/dist/assets/vi-VN-td08xXv9.js +0 -1
- package/apps/web/dist/assets/visual-editor-CzB_qwvB.js +0 -208
- package/apps/web/dist/assets/workspace-settings-DOr9j8X1.js +0 -1
- package/apps/web/dist/assets/zh-CN-D3dhEYLS.js +0 -1
- package/apps/web/dist/assets/zh-TW-CfhOEFo8.js +0 -1
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import i18next from "i18next";
|
|
3
|
+
//#region ../../packages/contracts/src/icons.ts
|
|
4
|
+
const ticketSymbols = {
|
|
5
|
+
status: {
|
|
6
|
+
backlog: {
|
|
7
|
+
icon: "circle-dashed",
|
|
8
|
+
tone: "muted"
|
|
9
|
+
},
|
|
10
|
+
todo: {
|
|
11
|
+
icon: "circle",
|
|
12
|
+
tone: "muted"
|
|
13
|
+
},
|
|
14
|
+
in_progress: {
|
|
15
|
+
icon: "circle-dot",
|
|
16
|
+
tone: "accent"
|
|
17
|
+
},
|
|
18
|
+
in_review: {
|
|
19
|
+
icon: "clock",
|
|
20
|
+
tone: "warning"
|
|
21
|
+
},
|
|
22
|
+
done: {
|
|
23
|
+
icon: "circle-check",
|
|
24
|
+
tone: "success"
|
|
25
|
+
},
|
|
26
|
+
cancelled: {
|
|
27
|
+
icon: "circle-x",
|
|
28
|
+
tone: "muted"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
priority: {
|
|
32
|
+
urgent: {
|
|
33
|
+
icon: "octagon-alert",
|
|
34
|
+
tone: "danger"
|
|
35
|
+
},
|
|
36
|
+
high: {
|
|
37
|
+
icon: "arrow-up",
|
|
38
|
+
tone: "warning"
|
|
39
|
+
},
|
|
40
|
+
medium: {
|
|
41
|
+
icon: "equal",
|
|
42
|
+
tone: "foreground"
|
|
43
|
+
},
|
|
44
|
+
low: {
|
|
45
|
+
icon: "arrow-down",
|
|
46
|
+
tone: "accent"
|
|
47
|
+
},
|
|
48
|
+
none: {
|
|
49
|
+
icon: "minus",
|
|
50
|
+
tone: "muted"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
kind: {
|
|
54
|
+
feature: {
|
|
55
|
+
icon: "sparkles",
|
|
56
|
+
tone: "muted"
|
|
57
|
+
},
|
|
58
|
+
bug: {
|
|
59
|
+
icon: "bug",
|
|
60
|
+
tone: "muted"
|
|
61
|
+
},
|
|
62
|
+
chore: {
|
|
63
|
+
icon: "wrench",
|
|
64
|
+
tone: "muted"
|
|
65
|
+
},
|
|
66
|
+
research: {
|
|
67
|
+
icon: "flask-conical",
|
|
68
|
+
tone: "muted"
|
|
69
|
+
},
|
|
70
|
+
documentation: {
|
|
71
|
+
icon: "book-open",
|
|
72
|
+
tone: "muted"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
3
77
|
//#region ../../packages/contracts/src/instance.ts
|
|
4
78
|
const endpoint$1 = z.url({ protocol: /^https?$/ }).refine((value) => !/^https?:\/\/[^/]*@/.test(value) && !/[?#]/.test(value), "Use an HTTP(S) endpoint without embedded credentials");
|
|
5
79
|
const s3SettingsSchema = z.object({
|
|
@@ -216,10 +290,15 @@ var en_US_default = {
|
|
|
216
290
|
priority: "Priority",
|
|
217
291
|
kind: "Kind",
|
|
218
292
|
difficulty: "Difficulty",
|
|
293
|
+
automation: "Agent readiness",
|
|
219
294
|
label: "Label",
|
|
220
295
|
assigneeId: "Assignee",
|
|
221
296
|
customField: "Field"
|
|
222
297
|
},
|
|
298
|
+
automationFilter: {
|
|
299
|
+
ready: "Ready for agents",
|
|
300
|
+
manual: "Needs a person"
|
|
301
|
+
},
|
|
223
302
|
sort: {
|
|
224
303
|
priority: "Priority",
|
|
225
304
|
updated: "Recently updated",
|
|
@@ -461,6 +540,7 @@ var en_US_default = {
|
|
|
461
540
|
time_entry_conflict: "This actor already has a running entry on the ticket.",
|
|
462
541
|
claim_conflict: "Another worker holds this ticket.",
|
|
463
542
|
idempotency_conflict: "This request was already used for another change.",
|
|
543
|
+
duplicate_repository: "Another project in this workspace links this repository.",
|
|
464
544
|
project_archived: "Restore the archived project before changing it.",
|
|
465
545
|
rate_limited: "Too many changes in a short time. Wait and retry.",
|
|
466
546
|
snapshot_required: "The live feed fell behind. Reload to continue.",
|
|
@@ -930,6 +1010,7 @@ var en_US_default = {
|
|
|
930
1010
|
},
|
|
931
1011
|
ticket: {
|
|
932
1012
|
list: {
|
|
1013
|
+
manageViews: "Manage views",
|
|
933
1014
|
selectSection: "Select {{section}} tickets",
|
|
934
1015
|
expandSection: "Expand {{section}} tickets",
|
|
935
1016
|
collapseSection: "Collapse {{section}} tickets",
|
|
@@ -1058,6 +1139,7 @@ var en_US_default = {
|
|
|
1058
1139
|
noDue: "No due date"
|
|
1059
1140
|
},
|
|
1060
1141
|
filter: {
|
|
1142
|
+
add: "Add filter",
|
|
1061
1143
|
me: "Me",
|
|
1062
1144
|
searchTickets: "Search tickets",
|
|
1063
1145
|
searchTicketsPlaceholder: "Search tickets…",
|
|
@@ -1086,6 +1168,7 @@ var en_US_default = {
|
|
|
1086
1168
|
priority: "All priorities",
|
|
1087
1169
|
kind: "All kinds",
|
|
1088
1170
|
difficulty: "All difficulties",
|
|
1171
|
+
automation: "Any readiness",
|
|
1089
1172
|
label: "All labels",
|
|
1090
1173
|
assigneeId: "Anyone",
|
|
1091
1174
|
customField: "Any field value"
|
|
@@ -1095,6 +1178,7 @@ var en_US_default = {
|
|
|
1095
1178
|
priority: "Search priorities",
|
|
1096
1179
|
kind: "Search kinds",
|
|
1097
1180
|
difficulty: "Search difficulties",
|
|
1181
|
+
automation: "Search readiness",
|
|
1098
1182
|
label: "Search labels",
|
|
1099
1183
|
assigneeId: "Search people",
|
|
1100
1184
|
customField: "Search fields"
|
|
@@ -1550,7 +1634,7 @@ var en_US_default = {
|
|
|
1550
1634
|
permission: {
|
|
1551
1635
|
intake: {
|
|
1552
1636
|
name: "Submit reports",
|
|
1553
|
-
description: "Create quarantined tickets only. Cannot read or edit tickets. Use alone."
|
|
1637
|
+
description: "Create quarantined tickets and attach files to them only. Cannot read or edit tickets. Use alone."
|
|
1554
1638
|
},
|
|
1555
1639
|
read: {
|
|
1556
1640
|
name: "Read tickets",
|
|
@@ -1627,6 +1711,9 @@ var en_US_default = {
|
|
|
1627
1711
|
changePrefixDescription: "Every ticket in {{name}} takes the new prefix and keeps its number.",
|
|
1628
1712
|
changing: "Changing…",
|
|
1629
1713
|
prefixChanged: "Tickets now use {{key}}",
|
|
1714
|
+
repositories: "Repositories",
|
|
1715
|
+
repositoriesDescription: "Agents can pass one of these git remotes as the project ID.",
|
|
1716
|
+
repositoriesInvalid: "Enter up to 20 git remotes, such as git@github.com:owner/repo.git.",
|
|
1630
1717
|
publicLink: "Public link",
|
|
1631
1718
|
publicDisclosure: "Anyone with the link can read every unarchived ticket's title, description, acceptance criteria, status, priority, kind, difficulty, labels, scopes, dates, and links to other tickets in this project. People, comments, activity, attachments, evidence, and claims stay private.",
|
|
1632
1719
|
publicOn: "Public link on",
|
|
@@ -2497,6 +2584,9 @@ var en_US_default = {
|
|
|
2497
2584
|
}
|
|
2498
2585
|
},
|
|
2499
2586
|
native: {
|
|
2587
|
+
"navigation.projectButton": "{{project}} ⌄",
|
|
2588
|
+
"navigation.recentProjects": "Recent projects",
|
|
2589
|
+
"navigation.switchProject": "Switch workspace or project",
|
|
2500
2590
|
labelValue: "{{label}}: {{value}}",
|
|
2501
2591
|
ui: {
|
|
2502
2592
|
dismiss: "Dismiss",
|
|
@@ -2545,6 +2635,10 @@ var en_US_default = {
|
|
|
2545
2635
|
create: "Create project"
|
|
2546
2636
|
},
|
|
2547
2637
|
tickets: {
|
|
2638
|
+
options: "List options",
|
|
2639
|
+
expandAll: "Expand all sections",
|
|
2640
|
+
collapseAll: "Collapse all sections",
|
|
2641
|
+
select: "Select tickets",
|
|
2548
2642
|
search: "Search tickets",
|
|
2549
2643
|
searchPlaceholder: "Title, description, or key",
|
|
2550
2644
|
allStatuses: "All statuses",
|
|
@@ -2671,6 +2765,7 @@ var en_US_default = {
|
|
|
2671
2765
|
next: "Next activity"
|
|
2672
2766
|
},
|
|
2673
2767
|
inbox: {
|
|
2768
|
+
read: "Read",
|
|
2674
2769
|
markAllRead: "Mark all read",
|
|
2675
2770
|
empty: "No notifications"
|
|
2676
2771
|
},
|
|
@@ -2853,8 +2948,10 @@ const scopes = [
|
|
|
2853
2948
|
];
|
|
2854
2949
|
const attachmentLimit = 1e7;
|
|
2855
2950
|
const stagedUploadLifetime = 864e5;
|
|
2951
|
+
const uploadUrlLifetime = 9e5;
|
|
2856
2952
|
const stateLabels = labelTable(states, (value) => t(`common.status.${value}`));
|
|
2857
2953
|
const priorityLabels = labelTable(priorities, (value) => t(`common.priority.${value}`));
|
|
2954
|
+
ticketSymbols.status.backlog.tone, ticketSymbols.status.todo.tone, ticketSymbols.status.in_progress.tone, ticketSymbols.status.in_review.tone, ticketSymbols.status.done.tone, ticketSymbols.status.cancelled.tone;
|
|
2858
2955
|
const id = z.string().min(1).max(80);
|
|
2859
2956
|
const timestamp = z.iso.datetime();
|
|
2860
2957
|
const version = z.number().int().positive();
|
|
@@ -2968,9 +3065,30 @@ const placement = {
|
|
|
2968
3065
|
after: id.optional()
|
|
2969
3066
|
};
|
|
2970
3067
|
const oneNeighbor = (input) => input.before === void 0 || input.after === void 0;
|
|
2971
|
-
const projectInput = z.object({ projectId:
|
|
3068
|
+
const projectInput = z.object({ projectId: z.string().min(1).max(300) });
|
|
2972
3069
|
const ticketInput = projectInput.extend({ ticketId: id });
|
|
2973
3070
|
const projectKey = z.string().trim().regex(/^[A-Z][A-Z0-9]{1,9}$/);
|
|
3071
|
+
const remoteHost = "(?<host>[a-z0-9][a-z0-9.-]*)";
|
|
3072
|
+
const remotePath = "(?<path>[^?#]+)";
|
|
3073
|
+
const remoteForms = [
|
|
3074
|
+
new RegExp(`^(?<scheme>https|ssh)://(?:[^/]*@)?${remoteHost}(?::(?<port>\\d+))?/${remotePath}$`),
|
|
3075
|
+
new RegExp(`^[^/:@]+@${remoteHost}:${remotePath}$`),
|
|
3076
|
+
new RegExp(`^${remoteHost}(?::(?<port>\\d+))?/${remotePath}$`)
|
|
3077
|
+
];
|
|
3078
|
+
const defaultRemotePorts = {
|
|
3079
|
+
https: "443",
|
|
3080
|
+
ssh: "22"
|
|
3081
|
+
};
|
|
3082
|
+
function normalizeRemote(value) {
|
|
3083
|
+
const remote = value.trim().toLowerCase();
|
|
3084
|
+
if (/\s/.test(remote)) return null;
|
|
3085
|
+
const { scheme, host, port, path } = remoteForms.map((form) => form.exec(remote)).find(Boolean)?.groups ?? {};
|
|
3086
|
+
const segments = path?.replace(/\/+$/, "").replace(/\.git$/, "").split("/").filter(Boolean);
|
|
3087
|
+
if (!host || !segments?.length) return null;
|
|
3088
|
+
return `${host}${port && port !== defaultRemotePorts[scheme ?? ""] ? `:${port}` : ""}/${segments.join("/")}`;
|
|
3089
|
+
}
|
|
3090
|
+
const repositoryRemote = z.string().max(300).refine((value) => normalizeRemote(value) !== null, "Enter a git remote URL").overwrite((value) => normalizeRemote(value) ?? value);
|
|
3091
|
+
const projectRepositories = z.array(repositoryRemote).max(20).overwrite((remotes) => [...new Set(remotes)]);
|
|
2974
3092
|
const reason = z.object({
|
|
2975
3093
|
code: z.string(),
|
|
2976
3094
|
message: z.string(),
|
|
@@ -2987,15 +3105,19 @@ const filterFieldNames = [
|
|
|
2987
3105
|
"priority",
|
|
2988
3106
|
"kind",
|
|
2989
3107
|
"difficulty",
|
|
3108
|
+
"automation",
|
|
2990
3109
|
"label",
|
|
2991
3110
|
"assigneeId",
|
|
2992
3111
|
"customField"
|
|
2993
3112
|
];
|
|
3113
|
+
const automationFilters = ["ready", "manual"];
|
|
3114
|
+
labelTable(automationFilters, (value) => t(`common.automationFilter.${value}`));
|
|
2994
3115
|
const filterFields = {
|
|
2995
3116
|
status: z.enum(states),
|
|
2996
3117
|
priority: z.enum(priorities),
|
|
2997
3118
|
kind: z.enum(kinds),
|
|
2998
3119
|
difficulty: z.enum(difficulties),
|
|
3120
|
+
automation: z.enum(automationFilters),
|
|
2999
3121
|
label: z.string().max(40),
|
|
3000
3122
|
assigneeId: z.union([id, z.literal("none")]),
|
|
3001
3123
|
customField: z.string().regex(/^[0-9a-f-]{36}:(?:none|true|[0-9a-f-]{36})$/)
|
|
@@ -3013,6 +3135,8 @@ const filterShape = {
|
|
|
3013
3135
|
kindNot: filterValues(filterFields.kind),
|
|
3014
3136
|
difficulty: filterValues(filterFields.difficulty),
|
|
3015
3137
|
difficultyNot: filterValues(filterFields.difficulty),
|
|
3138
|
+
automation: filterValues(filterFields.automation),
|
|
3139
|
+
automationNot: filterValues(filterFields.automation),
|
|
3016
3140
|
label: filterValues(filterFields.label),
|
|
3017
3141
|
labelNot: filterValues(filterFields.label),
|
|
3018
3142
|
assigneeId: filterValues(filterFields.assigneeId),
|
|
@@ -3082,6 +3206,7 @@ const ticketFilter = z.object({
|
|
|
3082
3206
|
]).default("priority"),
|
|
3083
3207
|
order: z.enum(["asc", "desc"]).optional()
|
|
3084
3208
|
}).strict().superRefine(rejectConflicts);
|
|
3209
|
+
const listSort = ticketFilter.shape.sort.unwrap().optional();
|
|
3085
3210
|
labelTable(ticketFilter.shape.sort.unwrap().options, (sort) => t(`common.sort.${sort}`));
|
|
3086
3211
|
const defaultOrder = {
|
|
3087
3212
|
priority: "asc",
|
|
@@ -3190,6 +3315,7 @@ const projectSchema = z.object({
|
|
|
3190
3315
|
key: z.string(),
|
|
3191
3316
|
name: z.string(),
|
|
3192
3317
|
description: z.string(),
|
|
3318
|
+
repositories: z.array(z.string()).default([]),
|
|
3193
3319
|
version,
|
|
3194
3320
|
archivedAt: timestamp.nullable().default(null),
|
|
3195
3321
|
createdAt: timestamp,
|
|
@@ -3360,6 +3486,11 @@ const attachmentSchema = z.object({
|
|
|
3360
3486
|
createdAt: timestamp
|
|
3361
3487
|
});
|
|
3362
3488
|
const stagedUploadSchema = attachmentSchema.omit({ ticketId: true }).extend({ expiresAt: timestamp });
|
|
3489
|
+
const uploadUrlSchema = z.object({
|
|
3490
|
+
uploadId: z.uuid(),
|
|
3491
|
+
url: z.url(),
|
|
3492
|
+
expiresAt: timestamp
|
|
3493
|
+
});
|
|
3363
3494
|
const httpUrl = z.url().regex(/^https?:\/\//i, "Use an HTTP or HTTPS URL");
|
|
3364
3495
|
const evidenceFields = z.object({
|
|
3365
3496
|
kind: z.enum([
|
|
@@ -4125,21 +4256,25 @@ const page = (item) => z.object({
|
|
|
4125
4256
|
items: z.array(item),
|
|
4126
4257
|
total: z.number().int().nonnegative()
|
|
4127
4258
|
});
|
|
4128
|
-
const
|
|
4259
|
+
const fileMetadata = {
|
|
4129
4260
|
name: text.max(255).refine((value) => {
|
|
4130
4261
|
for (const character of value) if (character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127) return false;
|
|
4131
4262
|
return true;
|
|
4132
4263
|
}, "Use a filename without control characters"),
|
|
4133
|
-
contentType: z.string().max(120).regex(/^[a-z0-9][a-z0-9.+-]*\/[a-z0-9][a-z0-9.+-]*$/i).default("application/octet-stream")
|
|
4264
|
+
contentType: z.string().max(120).regex(/^[a-z0-9][a-z0-9.+-]*\/[a-z0-9][a-z0-9.+-]*$/i).default("application/octet-stream")
|
|
4265
|
+
};
|
|
4266
|
+
const fileFields = {
|
|
4267
|
+
...fileMetadata,
|
|
4134
4268
|
data: z.string().max(Math.ceil(attachmentLimit / 3) * 4)
|
|
4135
4269
|
};
|
|
4136
|
-
const op = (input, output, method, path, scope, description) => ({
|
|
4270
|
+
const op = (input, output, method, path, scope, description, options = {}) => ({
|
|
4137
4271
|
input,
|
|
4138
4272
|
output,
|
|
4139
4273
|
method,
|
|
4140
4274
|
path,
|
|
4141
4275
|
scope,
|
|
4142
|
-
description
|
|
4276
|
+
description,
|
|
4277
|
+
...options
|
|
4143
4278
|
});
|
|
4144
4279
|
const operations = {
|
|
4145
4280
|
list_workspaces: op(z.object({}), z.array(workspaceSchema), "GET", "/workspaces", "read", "List accessible workspaces and the current membership role."),
|
|
@@ -4329,8 +4464,9 @@ const operations = {
|
|
|
4329
4464
|
publicReadEnabled: z.boolean().optional(),
|
|
4330
4465
|
name: text.max(120),
|
|
4331
4466
|
description: z.string().max(5e3),
|
|
4332
|
-
key: projectKey.optional()
|
|
4333
|
-
|
|
4467
|
+
key: projectKey.optional(),
|
|
4468
|
+
repositories: projectRepositories.optional()
|
|
4469
|
+
}).strict(), projectSchema, "PATCH", "/projects/{projectId}", "admin", "Update project details. A new `key` re-keys every ticket of the project; the previous prefix stays reserved for the project, and the project and every key issued under it keep resolving. `publicReadEnabled` shares or stops sharing the project's read-only public view (see the public operations). `repositories` replaces the project's linked git remotes (at most 20), and any `projectId` then accepts one of them; within a workspace only one unarchived project can hold a remote."),
|
|
4334
4470
|
move_project: op(projectInput.extend({
|
|
4335
4471
|
...mutation,
|
|
4336
4472
|
expectedVersion: version,
|
|
@@ -4394,13 +4530,14 @@ const operations = {
|
|
|
4394
4530
|
}).strict(), okSchema, "POST", "/projects/{projectId}/members", "admin", "Add or update an existing user's membership with a seeded role or a custom role of the project's workspace, or remove it with a null role. Needs `member.manage`; the role, and any role the person holds now, must grant nothing the caller lacks."),
|
|
4395
4531
|
list_tickets: op(projectInput.extend({
|
|
4396
4532
|
...ticketFilter.shape,
|
|
4533
|
+
sort: listSort,
|
|
4397
4534
|
...pagination,
|
|
4398
4535
|
relatedTo: id.optional(),
|
|
4399
4536
|
stateId: z.uuid().optional(),
|
|
4400
4537
|
scheduledFrom: timestamp.optional(),
|
|
4401
4538
|
scheduledTo: timestamp.optional(),
|
|
4402
4539
|
...ticketView
|
|
4403
|
-
}).superRefine(rejectConflicts), page(ticketRow), "GET", "/projects/{projectId}/tickets", "read", "Search tickets with server-side filters, stable ordering, and pagination. Each property filter takes one value or a repeated list (any of them); its `Not` twin excludes values.
|
|
4540
|
+
}).superRefine(rejectConflicts), page(ticketRow), "GET", "/projects/{projectId}/tickets", "read", "Search tickets with server-side filters, stable ordering, and pagination. Each property filter takes one value or a repeated list (any of them); its `Not` twin excludes values. `q` keeps only tickets whose key, title, description, acceptance criteria, labels, or scopes contain its text as written, or whose key or ID it names exactly; double-quoted segments are exact phrases that must each appear on word boundaries, so `\"IME\"` does not match `time` while unquoted `IME` does. With `q` and no `sort`, results order by relevance as in search_tickets; otherwise by `sort` (default `priority`). With `view: \"summary\"`, rows omit the description and acceptance criteria."),
|
|
4404
4541
|
list_ticket_labels: op(projectInput.extend({ archived: ticketFilter.shape.archived }), z.array(z.object({
|
|
4405
4542
|
name: z.string(),
|
|
4406
4543
|
count: z.number().int().nonnegative()
|
|
@@ -4494,7 +4631,7 @@ const operations = {
|
|
|
4494
4631
|
claim: claimSchema.nullable(),
|
|
4495
4632
|
subscribed: z.boolean(),
|
|
4496
4633
|
canReleaseClaim: z.boolean()
|
|
4497
|
-
}), "GET", "/projects/{projectId}/tickets/{ticketId}", "read", "Read a ticket by ID or key, with readiness and ownership."),
|
|
4634
|
+
}), "GET", "/projects/{projectId}/tickets/{ticketId}", "read", "Read a ticket by ID or key, with readiness and ownership.", { mcp: "core" }),
|
|
4498
4635
|
create_ticket: op(projectInput.extend({
|
|
4499
4636
|
...mutation,
|
|
4500
4637
|
title: ticketFields.shape.title,
|
|
@@ -4516,14 +4653,14 @@ const operations = {
|
|
|
4516
4653
|
archived: z.boolean().default(false),
|
|
4517
4654
|
uploads: z.array(z.uuid()).max(50).default([]),
|
|
4518
4655
|
customFields: customFieldValues.default({})
|
|
4519
|
-
}).strict(), ticketSchema, "POST", "/projects/{projectId}/tickets", "write", "Create a ticket. `customFields` maps field IDs from list_custom_fields to values; omitted fields take their default, and a required field must end with a value. `uploads` lists your staged inline uploads in this project; they become its attachments in the same write, or nothing is created. Reuse requestId when retrying this write."),
|
|
4656
|
+
}).strict(), ticketSchema, "POST", "/projects/{projectId}/tickets", "write", "Create a ticket. `customFields` maps field IDs from list_custom_fields to values; omitted fields take their default, and a required field must end with a value. `uploads` lists your staged inline uploads in this project; they become its attachments in the same write, or nothing is created. Reuse requestId when retrying this write.", { mcp: "core" }),
|
|
4520
4657
|
duplicate_ticket: op(ticketInput.extend(mutation).strict(), ticketSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/duplicate", "write", "Copy a ticket into a new To do ticket in the same project, linked to the original by a clones relationship. Copies requirements, properties, labels, scopes, and parent; resets agent readiness and never copies claims, comments, evidence, attachments, or children. Reuse requestId when retrying this write."),
|
|
4521
4658
|
update_ticket: op(ticketInput.extend({
|
|
4522
4659
|
...mutation,
|
|
4523
4660
|
expectedVersion: version,
|
|
4524
4661
|
changes: ticketChanges,
|
|
4525
4662
|
claimId: z.uuid().optional()
|
|
4526
|
-
}).strict(), ticketSchema, "PATCH", "/projects/{projectId}/tickets/{ticketId}", "write", "Update a ticket with optimistic concurrency. Worker completion requires its active claim. `changes.customFields` sets only the named fields; null clears one."),
|
|
4663
|
+
}).strict(), ticketSchema, "PATCH", "/projects/{projectId}/tickets/{ticketId}", "write", "Update a ticket with optimistic concurrency. Worker completion requires its active claim. `changes.customFields` sets only the named fields; null clears one.", { mcp: "core" }),
|
|
4527
4664
|
update_ticket_labels: op(ticketInput.extend({
|
|
4528
4665
|
...mutation,
|
|
4529
4666
|
expectedVersion: version,
|
|
@@ -4553,7 +4690,7 @@ const operations = {
|
|
|
4553
4690
|
resolve_ticket: op(z.object({ ticketId: id }).strict(), z.object({
|
|
4554
4691
|
ticket: ticketSchema,
|
|
4555
4692
|
project: projectRef
|
|
4556
|
-
}), "GET", "/tickets/resolve", "read", "Find a ticket by ID, current key, or any earlier key from a prefix change or a move, across every accessible project. An unknown or inaccessible ticket reads as not found."),
|
|
4693
|
+
}), "GET", "/tickets/resolve", "read", "Find a ticket by ID, current key, or any earlier key from a prefix change or a move, across every accessible project. An unknown or inaccessible ticket reads as not found.", { mcp: "core" }),
|
|
4557
4694
|
bulk_update_tickets: op(projectInput.extend({
|
|
4558
4695
|
...mutation,
|
|
4559
4696
|
tickets: claimedTicketSelection,
|
|
@@ -4576,7 +4713,7 @@ const operations = {
|
|
|
4576
4713
|
ticket: ticketRow,
|
|
4577
4714
|
project: projectRef,
|
|
4578
4715
|
snippet: z.string().optional()
|
|
4579
|
-
})) }), "GET", "/tickets/search", "read", "Search unarchived tickets by key or text across every accessible project, optionally within one workspace. Results order by exact key match, then relevance, then recency. Double-quoted segments of `q` match as exact phrases
|
|
4716
|
+
})) }), "GET", "/tickets/search", "read", "Search unarchived tickets by key or text across every accessible project, optionally within one workspace. Results order by exact key match, then relevance, then recency. Double-quoted segments of `q` match as exact phrases on word boundaries, so `\"IME\"` does not match `time`. With `view: \"summary\"`, each ticket is a compact row and the result carries a `snippet` of the matching text.", { mcp: "core" }),
|
|
4580
4717
|
search_workspace: op(z.object({
|
|
4581
4718
|
q: z.string().trim().min(1).max(200),
|
|
4582
4719
|
workspaceId: z.uuid().optional(),
|
|
@@ -4591,19 +4728,19 @@ const operations = {
|
|
|
4591
4728
|
counts: z.record(z.enum(searchResultTypes), z.number().int().nonnegative()),
|
|
4592
4729
|
engine: z.enum(["postgres", "index"]),
|
|
4593
4730
|
indexing: z.boolean()
|
|
4594
|
-
}), "GET", "/search", "read", "Search accessible tickets, projects, comments, and activity by text or ticket key, optionally within one workspace or one result type. Property filters restrict results to matching tickets. Results order by exact key match, then type, then ticket relevance, then recency. Double-quoted segments of `q` match ticket text as exact phrases.
|
|
4731
|
+
}), "GET", "/search", "read", "Search accessible tickets, projects, comments, and activity by text or ticket key, optionally within one workspace or one result type. Property filters restrict results to matching tickets. Results order by exact key match, then type, then ticket relevance, then recency. Double-quoted segments of `q` match ticket text as exact phrases on word boundaries. With `view: \"summary\"`, ticket results carry their summary row and each result a `snippet` of the matching text."),
|
|
4595
4732
|
list_my_work: op(z.object({
|
|
4596
4733
|
workspaceId: z.uuid().optional(),
|
|
4597
4734
|
q: ticketFilter.shape.q,
|
|
4598
|
-
sort:
|
|
4735
|
+
sort: listSort,
|
|
4599
4736
|
order: ticketFilter.shape.order,
|
|
4600
4737
|
activity: z.coerce.number().int().min(0).max(50).default(0),
|
|
4601
4738
|
...pagination
|
|
4602
|
-
}).strict(), page(ticketSchema).extend({ activity: z.array(eventSchema).default([]) }), "GET", "/my-work", "read", "List open, unarchived tickets assigned to the current identity across every accessible project, optionally within one workspace, with the most recent accessible activity when `activity` is set."),
|
|
4739
|
+
}).strict(), page(ticketSchema).extend({ activity: z.array(eventSchema).default([]) }), "GET", "/my-work", "read", "List open, unarchived tickets assigned to the current identity across every accessible project, optionally within one workspace, with the most recent accessible activity when `activity` is set. `q` and `sort` work as in list_tickets.", { mcp: "core" }),
|
|
4603
4740
|
list_eligible_tickets: op(projectInput.extend(pagination), page(z.object({
|
|
4604
4741
|
ticket: ticketSchema,
|
|
4605
4742
|
readiness: readinessSchema
|
|
4606
|
-
})), "GET", "/projects/{projectId}/eligibility", "read", "Inspect eligibility and explicit blocking reasons for open tickets."),
|
|
4743
|
+
})), "GET", "/projects/{projectId}/eligibility", "read", "Inspect eligibility and explicit blocking reasons for open tickets.", { mcp: "core" }),
|
|
4607
4744
|
list_relations: op(ticketInput, z.array(relationSchema), "GET", "/projects/{projectId}/tickets/{ticketId}/relations", "read", "List incoming and outgoing ticket relationships with each side's key, title, and project. A ticket in a project the caller cannot read appears by ID and key alone, with `restricted: true`."),
|
|
4608
4745
|
add_relation: op(ticketInput.extend({
|
|
4609
4746
|
...mutation,
|
|
@@ -4619,7 +4756,7 @@ const operations = {
|
|
|
4619
4756
|
add_comment: op(ticketInput.extend({
|
|
4620
4757
|
...mutation,
|
|
4621
4758
|
body: text.max(5e4)
|
|
4622
|
-
}).strict(), commentSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/comments", "write", "Add a comment with authenticated attribution. Mention a project member with `[@Name](mention:<user id>)` from list_members; members who can read the project are notified."),
|
|
4759
|
+
}).strict(), commentSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/comments", "write", "Add a comment with authenticated attribution. Mention a project member with `[@Name](mention:<user id>)` from list_members; members who can read the project are notified.", { mcp: "core" }),
|
|
4623
4760
|
update_comment: op(projectInput.extend({
|
|
4624
4761
|
...mutation,
|
|
4625
4762
|
commentId: z.uuid(),
|
|
@@ -4635,16 +4772,21 @@ const operations = {
|
|
|
4635
4772
|
upload_attachment: op(ticketInput.extend({
|
|
4636
4773
|
...mutation,
|
|
4637
4774
|
...fileFields
|
|
4638
|
-
}).strict(), attachmentSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/attachments", "write", "Upload up to 10 MB of base64-encoded bytes. The original filename is metadata, never a filesystem path."),
|
|
4775
|
+
}).strict(), attachmentSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/attachments", "write", "Upload up to 10 MB of base64-encoded bytes. The original filename is metadata, never a filesystem path. An intake credential can attach up to 10 files to a quarantined ticket it created, within 1 GB across its quarantined tickets. For a file on disk, use create_upload_url instead of inlining it."),
|
|
4639
4776
|
stage_upload: op(projectInput.extend({
|
|
4640
4777
|
...mutation,
|
|
4641
4778
|
...fileFields
|
|
4642
|
-
}).strict(), stagedUploadSchema, "POST", "/projects/{projectId}/uploads", "write", "Stage up to 10 MB of base64-encoded bytes for a ticket that does not exist yet. Only you can read it, at its attachment content address, until create_ticket claims it; unclaimed uploads expire after 24 hours."),
|
|
4779
|
+
}).strict(), stagedUploadSchema, "POST", "/projects/{projectId}/uploads", "write", "Stage up to 10 MB of base64-encoded bytes for a ticket that does not exist yet. Only you can read it, at its attachment content address, until create_ticket claims it; unclaimed uploads expire after 24 hours. For a file on disk, use create_upload_url instead of inlining it."),
|
|
4780
|
+
create_upload_url: op(projectInput.extend({
|
|
4781
|
+
...fileMetadata,
|
|
4782
|
+
ticketId: id.optional(),
|
|
4783
|
+
size: z.number().int().nonnegative().max(attachmentLimit)
|
|
4784
|
+
}).strict(), uploadUrlSchema, "POST", "/projects/{projectId}/upload-urls", "write", "Get a single-use URL for one file of up to 10 MB, so its bytes never pass through the tool call. PUT exactly `size` bytes to `url` within 15 minutes, for example `curl --upload-file <path> <url>`; the URL needs no other credential and reads nothing. With `ticketId` the file becomes that ticket's attachment; without it, it is a staged upload that create_ticket `uploads` claims by `uploadId`."),
|
|
4643
4785
|
discard_upload: op(projectInput.extend({
|
|
4644
4786
|
...mutation,
|
|
4645
4787
|
uploadId: z.uuid()
|
|
4646
4788
|
}).strict(), okSchema, "DELETE", "/projects/{projectId}/uploads/{uploadId}", "write", "Delete one of your unclaimed staged uploads and its bytes."),
|
|
4647
|
-
list_attachments: op(ticketInput, z.array(attachmentSchema), "GET", "/projects/{projectId}/tickets/{ticketId}/attachments", "read", "List authorized attachment metadata."),
|
|
4789
|
+
list_attachments: op(ticketInput, z.array(attachmentSchema), "GET", "/projects/{projectId}/tickets/{ticketId}/attachments", "read", "List authorized attachment metadata. An intake credential can list them on a quarantined ticket it created."),
|
|
4648
4790
|
delete_attachment: op(projectInput.extend({
|
|
4649
4791
|
...mutation,
|
|
4650
4792
|
attachmentId: z.uuid()
|
|
@@ -4654,7 +4796,7 @@ const operations = {
|
|
|
4654
4796
|
...mutation,
|
|
4655
4797
|
...evidenceFields.shape,
|
|
4656
4798
|
claimId: z.uuid().optional()
|
|
4657
|
-
}).strict(), evidenceSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/evidence", "write", "Attach evidence with its commit and provenance."),
|
|
4799
|
+
}).strict(), evidenceSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/evidence", "write", "Attach evidence with its commit and provenance.", { mcp: "core" }),
|
|
4658
4800
|
list_time_entries: op(ticketInput.extend(pagination), page(timeEntrySchema), "GET", "/projects/{projectId}/tickets/{ticketId}/time-entries", "read", "List observed time entries, newest first. Running entries have null endAt and durationMs."),
|
|
4659
4801
|
get_time_entry: op(ticketInput.extend({ timeEntryId: z.uuid() }), timeEntrySchema, "GET", "/projects/{projectId}/tickets/{ticketId}/time-entries/{timeEntryId}", "read", "Read one attributed time entry within its current ticket and project."),
|
|
4660
4802
|
create_time_entry: op(ticketInput.extend({
|
|
@@ -4700,18 +4842,18 @@ const operations = {
|
|
|
4700
4842
|
claim_ticket: op(ticketInput.extend({
|
|
4701
4843
|
...mutation,
|
|
4702
4844
|
workerId: text.max(200),
|
|
4703
|
-
expectedVersion: version,
|
|
4845
|
+
expectedVersion: version.optional(),
|
|
4704
4846
|
leaseSeconds: claimLeaseSecondsSchema.optional()
|
|
4705
|
-
}).strict(), claimSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/claim", "claim", "Atomically claim ready work. Expired claims require explicit recovery."),
|
|
4847
|
+
}).strict(), claimSchema.extend({ ticket: ticketSchema }), "POST", "/projects/{projectId}/tickets/{ticketId}/claim", "claim", "Atomically claim ready work and return the claim with the claimed ticket. expectedVersion is optional; readiness always applies. Expired claims require explicit recovery.", { mcp: "core" }),
|
|
4706
4848
|
renew_claim: op(ticketInput.extend({
|
|
4707
4849
|
...mutation,
|
|
4708
4850
|
claimId: z.uuid(),
|
|
4709
4851
|
leaseSeconds: claimLeaseSecondsSchema.optional()
|
|
4710
|
-
}).strict(), claimSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/claim/renew", "claim", "Renew the caller's unexpired claim."),
|
|
4852
|
+
}).strict(), claimSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/claim/renew", "claim", "Renew the caller's unexpired claim.", { mcp: "core" }),
|
|
4711
4853
|
release_claim: op(ticketInput.extend({
|
|
4712
4854
|
...mutation,
|
|
4713
4855
|
claimId: z.uuid()
|
|
4714
|
-
}).strict(), okSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/claim/release", "claim", "Release the caller's claim."),
|
|
4856
|
+
}).strict(), okSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/claim/release", "claim", "Release the caller's claim.", { mcp: "core" }),
|
|
4715
4857
|
recover_claim: op(ticketInput.extend({
|
|
4716
4858
|
...mutation,
|
|
4717
4859
|
claimId: z.uuid().optional(),
|
|
@@ -4999,4 +5141,4 @@ function parseOutput(name, value) {
|
|
|
4999
5141
|
return operations[name].output.parse(value);
|
|
5000
5142
|
}
|
|
5001
5143
|
//#endregion
|
|
5002
|
-
export {
|
|
5144
|
+
export { parseCustomFieldFilter as $, filterList as A, ticketImportSchema as At, isPublicOperation as B, instanceUpdateSchema as Bt, destinationKinds as C, stagedUploadLifetime as Ct, eventLabels as D, streamErrorSchema as Dt, eventCategories as E, states as Et, importSecretFields as F, workflowOrder as Ft, notificationIdsInput as G, searchSettingsSchema as Gt, memberSchema as H, photoResultSchema as Ht, invitationStatuses as I, workspaceSchema as It, notificationReadInput as J, notificationPreferencesInput as K, isHexColor as L, adminInstanceSchema as Lt, hasAdminRole as M, ticketSchema as Mt, importLimits as N, ticketSummarySchema as Nt, eventSchema as O, ticketExportFormat as Ot, importProviderDefinitions as P, uploadUrlLifetime as Pt, operations as Q, isOperation as R, authenticationPolicySchema as Rt, destinationEventKeys as S, snapshotSchema as St, errorSchema as T, stateLabels as Tt, mentionScheme as U, s3SettingsSchema as Ut, isSeededRole as V, photoInputSchema as Vt, normalizeRemote as W, searchAuthentication as Wt, okSchema as X, notificationsSchema as Y, operationPermission as Z, defaultOrder as _, roles as _t, channelRouteAllows as a, priorities as at, deliverySecretFields as b, seededPermissions as bt, claimSchema as c, publicOperations as ct, credentialProjectsSchema as d, repositoryProviderDefinitions as dt, parseOutput as et, customFieldFilterTokens as f, repositoryProviders as ft, defaultClaimMaxLeaseSeconds as g, roleLabels as gt, customFieldValueSchema as h, roleCategory as ht, channelKinds as i, permissions as it, formatEvent as j, ticketPredicates as jt, filterKey as k, ticketFilter as kt, closedStates as l, pushDeviceInput as lt, customFieldValue as m, resourceProvider as mt, attachmentLimit as n, permissionLabels as nt, checkpointSchema as o, priorityLabels as ot, customFieldSchema as p, repositorySecretFields as pt, notificationPreferencesSchema as q, attachmentSchema as r, permissionScope as rt, claimLeaseSecondsSchema as s, projectSchema as st, ApiError as t, parsePublicOutput as tt, credentialInput as u, remoteKinds as ut, defaultWorkflow as v, scopes as vt, difficulties as w, stagedUploadSchema as wt, deliverySettingsSchema as x, signInMethodLabels as xt, deletedAccountName as y, searchResultTypes as yt, isPresetColor as z, brokerSettingsSchema as zt };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TABLE "upload_urls" (
|
|
2
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
3
|
+
"project_id" uuid NOT NULL,
|
|
4
|
+
"ticket_id" uuid,
|
|
5
|
+
"actor_id" text NOT NULL,
|
|
6
|
+
"credential" jsonb,
|
|
7
|
+
"name" text NOT NULL,
|
|
8
|
+
"content_type" text NOT NULL,
|
|
9
|
+
"size" integer NOT NULL,
|
|
10
|
+
"token_hash" text NOT NULL,
|
|
11
|
+
"expires_at" timestamp with time zone NOT NULL,
|
|
12
|
+
"used_at" timestamp with time zone,
|
|
13
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
14
|
+
CONSTRAINT "upload_urls_token_hash_unique" UNIQUE("token_hash")
|
|
15
|
+
);
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
ALTER TABLE "upload_urls" ADD CONSTRAINT "upload_urls_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
18
|
+
ALTER TABLE "upload_urls" ADD CONSTRAINT "upload_urls_ticket_id_tickets_id_fk" FOREIGN KEY ("ticket_id") REFERENCES "public"."tickets"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
19
|
+
ALTER TABLE "upload_urls" ADD CONSTRAINT "upload_urls_actor_id_user_id_fk" FOREIGN KEY ("actor_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
20
|
+
CREATE INDEX "upload_urls_expires" ON "upload_urls" USING btree ("expires_at");
|