@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,7 +1,7 @@
|
|
|
1
|
-
import { a as auth_schema_exports, d as user$1, i as apikey, n as createDatabase, r as account, t as readConfig, u as session } from "./config-
|
|
2
|
-
import {
|
|
1
|
+
import { a as auth_schema_exports, d as user$1, i as apikey, n as createDatabase, r as account, t as readConfig, u as session } from "./config-CQVdVhXv.mjs";
|
|
2
|
+
import { B as isPublicOperation, Bt as instanceUpdateSchema, G as notificationIdsInput, Gt as searchSettingsSchema, H as memberSchema, Ht as photoResultSchema, J as notificationReadInput, K as notificationPreferencesInput, Lt as adminInstanceSchema, M as hasAdminRole, N as importLimits, Ot as ticketExportFormat, P as importProviderDefinitions, Q as operations, R as isOperation, T as errorSchema, Tt as stateLabels, Ut as s3SettingsSchema, Vt as photoInputSchema, X as okSchema, _t as roles, ct as publicOperations, l as closedStates, lt as pushDeviceInput, q as notificationPreferencesSchema, t as ApiError, u as credentialInput, v as defaultWorkflow, vt as scopes, z as isPresetColor, zt as brokerSettingsSchema } from "./src-D70GmZ5R.mjs";
|
|
3
3
|
import { t as migrateDatabase } from "./migrate-C9f4ozB4.mjs";
|
|
4
|
-
import { $ as
|
|
4
|
+
import { $ as pushDevices, A as requireInstanceAdmin, B as createPollingJob, C as defaultSenders, D as receiveUpload, E as createHttpSender, F as createBlobStorage, G as eventClock, H as attachments, I as decodeImage, J as members, K as events, L as imageResponse, M as readCalendarFeed, N as createTicketSearch, O as createAccess, P as createTicketIndex, Q as projects, R as stagedUploadCutoff, S as receiveRepositoryWebhook, T as DeliveryError, U as blobObjects, V as attachmentContent, W as deliveryCheckpoints, X as notifications, Y as notificationPreferences, Z as profilePhotos, _ as one, a as deliverySecrets, at as workspaces, b as requireRow, c as ownerBlocker, d as createDomain, et as stagedUploads, f as errorEnvelope, g as notify, h as json, i as createInstance, it as workspaceMembers, j as requireSession, k as createWriteLimiter, l as appendEvents, m as intakeOnly, n as emailCodesAvailable, nt as subscriptions, o as otherActiveAdministrator, ot as matchesOIDCBinding, p as fail, r as signInProviders, rt as tickets, s as ownedWorkspaces, t as createAuth, tt as storageBackends, u as assertVersion, v as reachable, w as deliverBatch, x as processImports, y as recipientColumns, z as createObjectStore } from "./auth-D43XyHdK.mjs";
|
|
5
5
|
import { serve } from "@hono/node-server";
|
|
6
6
|
import pg from "pg";
|
|
7
7
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
@@ -9,8 +9,8 @@ import { and, asc, count, desc, eq, gt, ilike, inArray, isNotNull, isNull, notIn
|
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
12
|
-
import { Expo } from "expo-server-sdk";
|
|
13
12
|
import { isDeepStrictEqual } from "node:util";
|
|
13
|
+
import { Expo } from "expo-server-sdk";
|
|
14
14
|
import { EventEmitter } from "node:events";
|
|
15
15
|
import { connect } from "amqplib";
|
|
16
16
|
import { OpenAPIHono, createRoute, z as z$1 } from "@hono/zod-openapi";
|
|
@@ -359,7 +359,7 @@ function createCleanup() {
|
|
|
359
359
|
}
|
|
360
360
|
//#endregion
|
|
361
361
|
//#region src/version.ts
|
|
362
|
-
const applicationVersion = "0.
|
|
362
|
+
const applicationVersion = "0.7.0";
|
|
363
363
|
//#endregion
|
|
364
364
|
//#region src/realtime.ts
|
|
365
365
|
async function createRealtime(config) {
|
|
@@ -3121,49 +3121,138 @@ const defaultAdapters = {
|
|
|
3121
3121
|
};
|
|
3122
3122
|
//#endregion
|
|
3123
3123
|
//#region src/mcp.ts
|
|
3124
|
+
const operationNames = Object.keys(operations).filter(isOperation);
|
|
3125
|
+
const coreNames = operationNames.filter((name) => operations[name].mcp === "core");
|
|
3126
|
+
const instructions = "Ticket keys look like KAN-12, and a key's prefix or the project's linked git remote works as projectId. To work a ticket: claim_ticket, keep its status current with update_ticket, add_comment on what you did, add_evidence, then set status done and release_claim. Leave tickets with automationReady false to people. The core tools are listed. Reach every other operation with find_operation, then read_operation for reads or run_operation for writes. In replies, a missing key means null or empty; lists return summary rows unless view is full.";
|
|
3127
|
+
const defaultView = "summary";
|
|
3128
|
+
const toolInput = (name) => {
|
|
3129
|
+
const input = operations[name].input;
|
|
3130
|
+
return "view" in input.shape ? input.safeExtend({ view: z.enum([defaultView, "full"]).default(defaultView) }) : input;
|
|
3131
|
+
};
|
|
3132
|
+
const echoedFields = (name) => {
|
|
3133
|
+
const { shape } = toolInput(name);
|
|
3134
|
+
const { changes } = shape;
|
|
3135
|
+
return ["description", "acceptanceCriteria"].filter((field) => field in shape || changes instanceof z.ZodObject && field in changes.shape);
|
|
3136
|
+
};
|
|
3137
|
+
const isEmpty = (value) => value === null || typeof value === "object" && Object.keys(value).length === 0;
|
|
3138
|
+
const compact = (value, echoed) => {
|
|
3139
|
+
if (Array.isArray(value)) return value.map((item) => compact(item, echoed));
|
|
3140
|
+
if (typeof value !== "object" || value === null) return value;
|
|
3141
|
+
const dropped = "acceptanceCriteria" in value ? echoed : [];
|
|
3142
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => !dropped.includes(key)).map(([key, field]) => [key, compact(field, echoed)]).filter(([, field]) => !isEmpty(field)));
|
|
3143
|
+
};
|
|
3144
|
+
const known = (name) => {
|
|
3145
|
+
if (!isOperation(name)) throw new ApiError(404, "not_found", `No operation is named ${name}`);
|
|
3146
|
+
return name;
|
|
3147
|
+
};
|
|
3148
|
+
const summary = (name) => ({
|
|
3149
|
+
name,
|
|
3150
|
+
description: operations[name].description,
|
|
3151
|
+
access: operations[name].method === "GET" ? "read" : "write"
|
|
3152
|
+
});
|
|
3153
|
+
function findOperation({ query = "", name }) {
|
|
3154
|
+
if (name !== void 0) {
|
|
3155
|
+
const operation = known(name), spec = operations[operation];
|
|
3156
|
+
return {
|
|
3157
|
+
...summary(operation),
|
|
3158
|
+
method: spec.method,
|
|
3159
|
+
scope: spec.scope,
|
|
3160
|
+
inputSchema: z.toJSONSchema(toolInput(operation), { io: "input" })
|
|
3161
|
+
};
|
|
3162
|
+
}
|
|
3163
|
+
const terms = query.toLowerCase().split(/\s+/);
|
|
3164
|
+
return { operations: operationNames.map(summary).filter((row) => terms.every((term) => `${row.name} ${row.description}`.toLowerCase().includes(term))) };
|
|
3165
|
+
}
|
|
3166
|
+
const reply = async (name, work) => {
|
|
3167
|
+
try {
|
|
3168
|
+
return {
|
|
3169
|
+
content: [{
|
|
3170
|
+
type: "text",
|
|
3171
|
+
text: `${name} completed.`
|
|
3172
|
+
}],
|
|
3173
|
+
structuredContent: { result: await work() }
|
|
3174
|
+
};
|
|
3175
|
+
} catch (error) {
|
|
3176
|
+
return {
|
|
3177
|
+
isError: true,
|
|
3178
|
+
content: [{
|
|
3179
|
+
type: "text",
|
|
3180
|
+
text: JSON.stringify(errorEnvelope(error).body)
|
|
3181
|
+
}]
|
|
3182
|
+
};
|
|
3183
|
+
}
|
|
3184
|
+
};
|
|
3185
|
+
const runnerInput = {
|
|
3186
|
+
name: z.string().max(80).describe("Operation name from find_operation."),
|
|
3187
|
+
input: z.record(z.string(), z.unknown()).default({}).describe("The operation's input.")
|
|
3188
|
+
};
|
|
3124
3189
|
function createMcp(auth, domain, access, config, limitWrite) {
|
|
3125
|
-
const serve = (request, identity, limited = false) =>
|
|
3126
|
-
const
|
|
3127
|
-
name
|
|
3128
|
-
|
|
3190
|
+
const serve = (request, identity, limited = false) => {
|
|
3191
|
+
const execute = async (name, input) => {
|
|
3192
|
+
if (limited && operations[name].method !== "GET") limitWrite(identity.ownerId);
|
|
3193
|
+
const value = "view" in operations[name].input.shape ? {
|
|
3194
|
+
view: defaultView,
|
|
3195
|
+
...input
|
|
3196
|
+
} : input;
|
|
3197
|
+
return compact(await domain.execute(name, value, identity), echoedFields(name));
|
|
3198
|
+
};
|
|
3199
|
+
const runner = (write) => (args) => reply(args.name, () => {
|
|
3200
|
+
const name = known(args.name);
|
|
3201
|
+
if (operations[name].method !== "GET" !== write) throw new ApiError(400, "invalid_request", `${name} ${write ? "only reads; use read_operation" : "writes; use run_operation"}`);
|
|
3202
|
+
return execute(name, args.input);
|
|
3129
3203
|
});
|
|
3130
|
-
|
|
3131
|
-
const
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3204
|
+
return createMcpHandler(() => {
|
|
3205
|
+
const server = new McpServer({
|
|
3206
|
+
name: "Kanvil",
|
|
3207
|
+
version: applicationVersion
|
|
3208
|
+
}, { instructions });
|
|
3209
|
+
for (const name of coreNames) {
|
|
3210
|
+
const spec = operations[name];
|
|
3211
|
+
const inputSchema = toolInput(name).shape;
|
|
3212
|
+
server.registerTool(name, {
|
|
3213
|
+
description: spec.description,
|
|
3214
|
+
inputSchema,
|
|
3215
|
+
annotations: {
|
|
3216
|
+
readOnlyHint: spec.method === "GET",
|
|
3217
|
+
destructiveHint: false,
|
|
3218
|
+
idempotentHint: spec.method === "GET",
|
|
3219
|
+
openWorldHint: false
|
|
3220
|
+
}
|
|
3221
|
+
}, (input) => reply(name, () => execute(name, input)));
|
|
3222
|
+
}
|
|
3223
|
+
server.registerTool("find_operation", {
|
|
3224
|
+
description: "Find an operation that is not a listed tool. `query` matches names and descriptions and marks each match as read or write; `name` returns one operation with its input JSON Schema, method, and scope.",
|
|
3225
|
+
inputSchema: {
|
|
3226
|
+
query: z.string().max(200).optional(),
|
|
3227
|
+
name: z.string().max(80).optional()
|
|
3228
|
+
},
|
|
3137
3229
|
annotations: {
|
|
3138
|
-
readOnlyHint:
|
|
3139
|
-
|
|
3140
|
-
idempotentHint: spec.method === "GET",
|
|
3230
|
+
readOnlyHint: true,
|
|
3231
|
+
idempotentHint: true,
|
|
3141
3232
|
openWorldHint: false
|
|
3142
3233
|
}
|
|
3143
|
-
},
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
}],
|
|
3152
|
-
structuredContent: { result }
|
|
3153
|
-
};
|
|
3154
|
-
} catch (error) {
|
|
3155
|
-
return {
|
|
3156
|
-
isError: true,
|
|
3157
|
-
content: [{
|
|
3158
|
-
type: "text",
|
|
3159
|
-
text: JSON.stringify(errorEnvelope(error).body)
|
|
3160
|
-
}]
|
|
3161
|
-
};
|
|
3234
|
+
}, (input) => reply("find_operation", () => findOperation(input)));
|
|
3235
|
+
server.registerTool("read_operation", {
|
|
3236
|
+
description: "Run a read operation found with find_operation.",
|
|
3237
|
+
inputSchema: runnerInput,
|
|
3238
|
+
annotations: {
|
|
3239
|
+
readOnlyHint: true,
|
|
3240
|
+
idempotentHint: true,
|
|
3241
|
+
openWorldHint: false
|
|
3162
3242
|
}
|
|
3163
|
-
});
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3243
|
+
}, runner(false));
|
|
3244
|
+
server.registerTool("run_operation", {
|
|
3245
|
+
description: "Run a write operation found with find_operation.",
|
|
3246
|
+
inputSchema: runnerInput,
|
|
3247
|
+
annotations: {
|
|
3248
|
+
readOnlyHint: false,
|
|
3249
|
+
destructiveHint: true,
|
|
3250
|
+
openWorldHint: false
|
|
3251
|
+
}
|
|
3252
|
+
}, runner(true));
|
|
3253
|
+
return server;
|
|
3254
|
+
}, { legacy: "stateless" }).fetch(request);
|
|
3255
|
+
};
|
|
3167
3256
|
const oauth = requireMcpAuth(auth, async (request, claims) => {
|
|
3168
3257
|
if (typeof claims.sub !== "string") throw new ApiError(401, "unauthorized", "A user subject is required");
|
|
3169
3258
|
const granted = typeof claims.scope === "string" ? claims.scope.split(" ") : [];
|
|
@@ -3319,13 +3408,14 @@ async function initializeApplication(database, config, adapters, cleanup) {
|
|
|
3319
3408
|
} }, { status: 400 });
|
|
3320
3409
|
} });
|
|
3321
3410
|
app.use("*", secureHeaders());
|
|
3322
|
-
|
|
3411
|
+
const limitBody = bodyLimit({
|
|
3323
3412
|
maxSize: 15e6,
|
|
3324
3413
|
onError: () => Response.json({ error: {
|
|
3325
3414
|
code: "payload_too_large",
|
|
3326
3415
|
message: "The request exceeds the upload limit"
|
|
3327
3416
|
} }, { status: 413 })
|
|
3328
|
-
})
|
|
3417
|
+
});
|
|
3418
|
+
app.use("*", (c, next) => c.req.path.startsWith("/api/uploads/") ? next() : limitBody(c, next));
|
|
3329
3419
|
app.onError((error) => {
|
|
3330
3420
|
if (error instanceof APIError && error.statusCode >= 400 && error.statusCode < 500) return Response.json({ error: {
|
|
3331
3421
|
code: typeof error.body?.code === "string" ? error.body.code : "authentication_error",
|
|
@@ -3421,6 +3511,33 @@ async function initializeApplication(database, config, adapters, cleanup) {
|
|
|
3421
3511
|
"Referrer-Policy": "no-referrer"
|
|
3422
3512
|
} });
|
|
3423
3513
|
});
|
|
3514
|
+
app.openAPIRegistry.registerPath({
|
|
3515
|
+
method: "put",
|
|
3516
|
+
path: "/api/uploads/{token}",
|
|
3517
|
+
request: {
|
|
3518
|
+
params: z$1.object({ token: z$1.string() }),
|
|
3519
|
+
body: { content: { "application/octet-stream": { schema: z$1.string() } } }
|
|
3520
|
+
},
|
|
3521
|
+
responses: {
|
|
3522
|
+
200: { description: "The staged upload, or the attachment when the URL names a ticket" },
|
|
3523
|
+
400: { description: "The body or its Content-Length is not the declared size" },
|
|
3524
|
+
404: { description: "Unknown upload URL" },
|
|
3525
|
+
410: { description: "The upload URL was already used or expired" }
|
|
3526
|
+
}
|
|
3527
|
+
});
|
|
3528
|
+
app.put("/api/uploads/:token", async (c) => Response.json(await receiveUpload(domain, c.req.param("token"), c.req.header("content-length"), async (limit) => {
|
|
3529
|
+
const chunks = [], reader = c.req.raw.body?.getReader();
|
|
3530
|
+
if (!reader) return Buffer.alloc(0);
|
|
3531
|
+
let total = 0;
|
|
3532
|
+
while (total <= limit) {
|
|
3533
|
+
const { done, value } = await reader.read();
|
|
3534
|
+
if (done) return Buffer.concat(chunks);
|
|
3535
|
+
chunks.push(value);
|
|
3536
|
+
total += value.length;
|
|
3537
|
+
}
|
|
3538
|
+
await reader.cancel();
|
|
3539
|
+
return Buffer.concat(chunks);
|
|
3540
|
+
})));
|
|
3424
3541
|
app.openAPIRegistry.registerPath({
|
|
3425
3542
|
method: "post",
|
|
3426
3543
|
path: "/api/repository-hooks/{connectionId}",
|
|
@@ -3436,10 +3553,15 @@ async function initializeApplication(database, config, adapters, cleanup) {
|
|
|
3436
3553
|
const result = await receiveRepositoryWebhook(domain, repositories, secrets, c.req.param("connectionId"), c.req.raw.headers, await c.req.text());
|
|
3437
3554
|
return c.json(result, result.outcome === "duplicate" ? 200 : 202);
|
|
3438
3555
|
});
|
|
3556
|
+
const intakeRoutes = [
|
|
3557
|
+
["POST", /^\/api\/v1\/projects\/[^/]+\/tickets$/],
|
|
3558
|
+
["POST", /^\/api\/v1\/projects\/[^/]+\/tickets\/[^/]+\/attachments$/],
|
|
3559
|
+
["GET", /^\/api\/v1\/projects\/[^/]+\/tickets\/[^/]+\/attachments$/]
|
|
3560
|
+
];
|
|
3439
3561
|
app.use("/api/v1/*", async (c, next) => {
|
|
3440
3562
|
access.checkOrigin(c.req.raw);
|
|
3441
3563
|
const actor = await access.authenticate(c.req.raw);
|
|
3442
|
-
if (intakeOnly(actor) && !(c.req.method ===
|
|
3564
|
+
if (intakeOnly(actor) && !intakeRoutes.some(([method, path]) => c.req.method === method && path.test(c.req.path))) fail(403, "insufficient_scope", "Intake credentials can only create tickets and attach files to them");
|
|
3443
3565
|
c.set("actor", actor);
|
|
3444
3566
|
if (!actor.machine && ![
|
|
3445
3567
|
"GET",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createDatabase, t as readConfig } from "./config-
|
|
1
|
+
import { n as createDatabase, t as readConfig } from "./config-CQVdVhXv.mjs";
|
|
2
2
|
import { t as migrateDatabase } from "./migrate-C9f4ozB4.mjs";
|
|
3
3
|
//#region src/cli/migrate.ts
|
|
4
4
|
const database = createDatabase(readConfig());
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { d as user, n as createDatabase, r as account, t as readConfig, u as session } from "./config-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { d as user, n as createDatabase, r as account, t as readConfig, u as session } from "./config-CQVdVhXv.mjs";
|
|
2
|
+
import { M as hasAdminRole } from "./src-D70GmZ5R.mjs";
|
|
3
|
+
import { p as fail, q as instanceSettings, t as createAuth } from "./auth-D43XyHdK.mjs";
|
|
4
4
|
import { and, eq, isNull, sql } from "drizzle-orm";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { parseArgs } from "node:util";
|