@zonease/happy 0.6.45 → 0.6.47
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/dist/{api-Cj4RF4ga.mjs → api-L9jLLtI1.mjs} +2 -2
- package/dist/{api-CPQUJQGJ.cjs → api-mv48hjhj.cjs} +3 -3
- package/dist/{auth-Bk9bRj3Q.cjs → auth-0qbD9TEm.cjs} +4 -4
- package/dist/{auth-BxRfxsPn.mjs → auth-BoWfky2q.mjs} +2 -2
- package/dist/{auth-Du-LmcLH.cjs → auth-DfQYhTlg.cjs} +2 -2
- package/dist/{auth-Byjbkudh.mjs → auth-InL7fBsz.mjs} +4 -4
- package/dist/{browser-CBrNk2b6.cjs → browser-CF-r2ami.cjs} +1 -1
- package/dist/{browser-CrNqwWO0.mjs → browser-D9jMe1me.mjs} +1 -1
- package/dist/{claudeLocal-CR1aG4FT.mjs → claudeLocal-CFEXiYts.mjs} +1 -1
- package/dist/{claudeLocal-DMn1kiJq.cjs → claudeLocal-DOfhf6VK.cjs} +1 -1
- package/dist/codex/happyMcpStdioBridge.cjs +18 -1
- package/dist/codex/happyMcpStdioBridge.mjs +18 -1
- package/dist/{config-DIUIjSc3.mjs → config-BBm54d_L.mjs} +1 -1
- package/dist/{config-DfXlAE9f.cjs → config-ByyclMMi.cjs} +1 -1
- package/dist/{connect-Blv2AOQ7.mjs → connect-B5JhnDTy.mjs} +4 -4
- package/dist/{connect-DxKG4c89.cjs → connect-CIOfZYj-.cjs} +4 -4
- package/dist/{controlClient-Aga5KOuL.cjs → controlClient-DMEMVw4Y.cjs} +1 -1
- package/dist/{controlClient-D-5BGcGC.mjs → controlClient-P5wJhu1R.mjs} +1 -1
- package/dist/{cursorApprovalHook-DhdW7SxP.cjs → cursorApprovalHook-C9mdmRIx.cjs} +2 -2
- package/dist/{cursorApprovalHook-G462ilpH.mjs → cursorApprovalHook-DplHRbGK.mjs} +2 -2
- package/dist/{cursorApprovalServer-DJDjSGu1.cjs → cursorApprovalServer-BoI6qBTg.cjs} +1 -1
- package/dist/{cursorApprovalServer-CajHEZIy.mjs → cursorApprovalServer-C9y5dYDE.mjs} +1 -1
- package/dist/{deviceKeys-DjItabvw.cjs → deviceKeys-CzqNNlG1.cjs} +2 -2
- package/dist/{deviceKeys-DL_YhAVs.mjs → deviceKeys-tcvwm4KA.mjs} +2 -2
- package/dist/{doctor-s5r5tBV2.cjs → doctor-CBbj6YEl.cjs} +2 -2
- package/dist/{doctor-DpCWRLts.mjs → doctor-CXYhUN9A.mjs} +2 -2
- package/dist/{downloadImage-AYf-3ZYW.cjs → downloadImage-CRkycWIl.cjs} +1 -1
- package/dist/{downloadImage-aU6-_LTd.mjs → downloadImage-CpnQ3aS1.mjs} +1 -1
- package/dist/{enroll-AafyH7YB.mjs → enroll-CYNDVSIH.mjs} +3 -3
- package/dist/{enroll-DDmZIfwr.cjs → enroll-CyikRwm7.cjs} +3 -3
- package/dist/{evidence-BeL77p_3.cjs → evidence-CuGxhBQm.cjs} +1 -1
- package/dist/{evidence-s4HSdwJW.mjs → evidence-DAu9vtgh.mjs} +1 -1
- package/dist/{formatImageMessage-D09-zSuq.cjs → formatImageMessage-CqonqpiB.cjs} +1 -1
- package/dist/{formatImageMessage-X7lBbNk9.mjs → formatImageMessage-ZJZza9-9.mjs} +1 -1
- package/dist/index.cjs +46 -46
- package/dist/index.mjs +46 -46
- package/dist/{install-D3-4H76L.mjs → install-5H5Lh58Z.mjs} +2 -2
- package/dist/{install-MLAZRCd1.mjs → install-Cma2vLWa.mjs} +1 -1
- package/dist/{install-CUhg7JSa.cjs → install-X4JLGAi3.cjs} +2 -2
- package/dist/{install-CV4tyU-f.cjs → install-_GiK-K1X.cjs} +1 -1
- package/dist/lib.cjs +3 -3
- package/dist/lib.mjs +3 -3
- package/dist/{loadableToolOutput-B8h8vRAi.mjs → loadableToolOutput-4qF6EX0y.mjs} +2 -2
- package/dist/{loadableToolOutput-CyxrSX6o.cjs → loadableToolOutput-sf6E72GE.cjs} +2 -2
- package/dist/{persistence-C8YmO6e-.cjs → persistence-B_w4o5z-.cjs} +1 -1
- package/dist/{persistence-CIuIRPwE.mjs → persistence-D2aRTiT1.mjs} +1 -1
- package/dist/{push-CmNOCsuP.mjs → push-BiBqn-pk.mjs} +6 -6
- package/dist/{push-C3zA8d8v.cjs → push-Df6QabEp.cjs} +6 -6
- package/dist/{registerKillSessionHandler-CH_7VXKc.mjs → registerKillSessionHandler-AcpB6OSk.mjs} +130 -9
- package/dist/{registerKillSessionHandler-LeIqHfbo.cjs → registerKillSessionHandler-DUrOhiGo.cjs} +129 -8
- package/dist/{run-C4WAd7tO.mjs → run-D6oXm1Jk.mjs} +8 -8
- package/dist/{run-0LQDK84Z.cjs → run-DclH1MRm.cjs} +8 -8
- package/dist/{runClaude-CUKs1uIM.mjs → runClaude--M8lVtqr.mjs} +15 -15
- package/dist/{runClaude-C35zHmK5.cjs → runClaude-BfLi7f2N.cjs} +16 -16
- package/dist/{runCodex-DyZ2jjPq.mjs → runCodex-DatWk57y.mjs} +15 -15
- package/dist/{runCodex-DqH5zG0r.cjs → runCodex-DdcEe5bM.cjs} +15 -15
- package/dist/{runCursor-CUYlNNzB.cjs → runCursor-CszdTKDp.cjs} +14 -14
- package/dist/{runCursor-DBJr4Grx.mjs → runCursor-DxcT7Qtj.mjs} +14 -14
- package/dist/{runGemini-wXzzfjlb.mjs → runGemini-41p6X_zo.mjs} +26 -18
- package/dist/{runGemini-DR8URN73.cjs → runGemini-sAOJNh2V.cjs} +26 -18
- package/dist/{runOneShot-C7rpjuvK.mjs → runOneShot-NBUWEobi.mjs} +2 -2
- package/dist/{runOneShot-CyQgMHdu.cjs → runOneShot-m6HO3H5c.cjs} +2 -2
- package/dist/{serve-9sPqPPfs.mjs → serve-B84oK7m-.mjs} +6 -6
- package/dist/{serve-CLUZny1h.cjs → serve-CUNdZ2ps.cjs} +6 -6
- package/dist/{session-DwFwW1If.mjs → session-9-fr4sTn.mjs} +5 -5
- package/dist/{session-DsK6TYKl.cjs → session-De8UTFFI.cjs} +5 -5
- package/dist/{sessionKeyCache-Jman_FzK.mjs → sessionKeyCache-CEJH5cHj.mjs} +1 -1
- package/dist/{sessionKeyCache-CCCCQahC.cjs → sessionKeyCache-DYuPkw5Z.cjs} +1 -1
- package/dist/{sessionList-CRAr1LIi.mjs → sessionList-Dd4fyhNe.mjs} +2 -2
- package/dist/{sessionList-jb1iwUO8.cjs → sessionList-KhgmL10v.cjs} +2 -2
- package/dist/{sessionSummary-By9LYnr1.mjs → sessionSummary-CYsvjLpK.mjs} +3 -3
- package/dist/{sessionSummary-C4ttdYkc.cjs → sessionSummary-u-kSmPto.cjs} +3 -3
- package/dist/{setupOfflineReconnection-B8LXjrYU.mjs → setupOfflineReconnection-2m0GAIU5.mjs} +3 -3
- package/dist/{setupOfflineReconnection-EeK8Zibv.cjs → setupOfflineReconnection-BkAr6jAB.cjs} +3 -3
- package/dist/{spawnHappyCLI-ZuC3trh3.mjs → spawnHappyCLI-CG_S7LH1.mjs} +1 -1
- package/dist/{spawnHappyCLI-DH1071fN.cjs → spawnHappyCLI-T9EQFmAR.cjs} +1 -1
- package/dist/{ssh-bVM6-eHl.mjs → ssh-BTVqCokU.mjs} +5 -5
- package/dist/{ssh-DsBRhE6K.cjs → ssh-C4nI67Vq.cjs} +5 -5
- package/dist/{task-rXw2soeh.cjs → task-AWrQbs-h.cjs} +6 -6
- package/dist/{task-QsscHPOu.mjs → task-DzqzVDDn.mjs} +6 -6
- package/dist/{uninstall-D-DMUz_6.mjs → uninstall-394a0fgf.mjs} +2 -2
- package/dist/{uninstall-CFVmL2EA.cjs → uninstall-BRDV8214.cjs} +2 -2
- package/dist/{update-lVVrNorG.cjs → update-CZIaB80S.cjs} +3 -3
- package/dist/{update-CS-sauOX.mjs → update-DLqQQtYc.mjs} +3 -3
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { stat, readFile } from 'node:fs/promises';
|
|
2
2
|
import { io } from 'socket.io-client';
|
|
3
|
-
import { c as configuration, e as encodeBase64, f as encrypt, g as decrypt, h as decodeBase64 } from './persistence-
|
|
4
|
-
import { resolveDeviceForCommand } from './ssh-
|
|
3
|
+
import { c as configuration, e as encodeBase64, f as encrypt, g as decrypt, h as decodeBase64 } from './persistence-D2aRTiT1.mjs';
|
|
4
|
+
import { resolveDeviceForCommand } from './ssh-BTVqCokU.mjs';
|
|
5
5
|
import 'node:fs';
|
|
6
6
|
import 'node:os';
|
|
7
7
|
import 'node:path';
|
|
@@ -10,16 +10,16 @@ import 'node:crypto';
|
|
|
10
10
|
import 'tweetnacl';
|
|
11
11
|
import 'chalk';
|
|
12
12
|
import 'fs';
|
|
13
|
-
import './deviceKeys-
|
|
13
|
+
import './deviceKeys-tcvwm4KA.mjs';
|
|
14
14
|
import 'axios';
|
|
15
|
-
import './auth-
|
|
15
|
+
import './auth-BoWfky2q.mjs';
|
|
16
16
|
import 'qrcode-terminal';
|
|
17
17
|
import './time-DgsBLJA_.mjs';
|
|
18
|
-
import './browser-
|
|
18
|
+
import './browser-D9jMe1me.mjs';
|
|
19
19
|
import 'open';
|
|
20
20
|
import 'react';
|
|
21
21
|
import 'ink';
|
|
22
|
-
import './controlClient-
|
|
22
|
+
import './controlClient-P5wJhu1R.mjs';
|
|
23
23
|
import './projectPath-BTBIMB57.mjs';
|
|
24
24
|
import 'path';
|
|
25
25
|
import 'url';
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var promises = require('node:fs/promises');
|
|
4
4
|
var socket_ioClient = require('socket.io-client');
|
|
5
|
-
var logger = require('./persistence-
|
|
6
|
-
var ssh = require('./ssh-
|
|
5
|
+
var logger = require('./persistence-B_w4o5z-.cjs');
|
|
6
|
+
var ssh = require('./ssh-C4nI67Vq.cjs');
|
|
7
7
|
require('node:fs');
|
|
8
8
|
require('node:os');
|
|
9
9
|
require('node:path');
|
|
@@ -12,16 +12,16 @@ require('node:crypto');
|
|
|
12
12
|
require('tweetnacl');
|
|
13
13
|
require('chalk');
|
|
14
14
|
require('fs');
|
|
15
|
-
require('./deviceKeys-
|
|
15
|
+
require('./deviceKeys-CzqNNlG1.cjs');
|
|
16
16
|
require('axios');
|
|
17
|
-
require('./auth-
|
|
17
|
+
require('./auth-DfQYhTlg.cjs');
|
|
18
18
|
require('qrcode-terminal');
|
|
19
19
|
require('./time-Bj2HRkKH.cjs');
|
|
20
|
-
require('./browser-
|
|
20
|
+
require('./browser-CF-r2ami.cjs');
|
|
21
21
|
require('open');
|
|
22
22
|
require('react');
|
|
23
23
|
require('ink');
|
|
24
|
-
require('./controlClient-
|
|
24
|
+
require('./controlClient-DMEMVw4Y.cjs');
|
|
25
25
|
require('./projectPath-ChLhdOyt.cjs');
|
|
26
26
|
require('path');
|
|
27
27
|
require('url');
|
package/dist/{registerKillSessionHandler-CH_7VXKc.mjs → registerKillSessionHandler-AcpB6OSk.mjs}
RENAMED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { join, resolve, dirname } from 'node:path';
|
|
1
|
+
import { extname, basename, join, resolve, dirname } from 'node:path';
|
|
2
2
|
import { p as projectPath } from './projectPath-BTBIMB57.mjs';
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
import { createServer } from 'node:http';
|
|
5
5
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
6
6
|
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
import { c as configuration, l as logger, r as readCredentials } from './persistence-
|
|
9
|
-
import { l as listDevices, d as deviceExec } from './deviceKeys-
|
|
8
|
+
import { c as configuration, l as logger, r as readCredentials } from './persistence-D2aRTiT1.mjs';
|
|
9
|
+
import { l as listDevices, d as deviceExec } from './deviceKeys-tcvwm4KA.mjs';
|
|
10
10
|
import axios from 'axios';
|
|
11
|
+
import { stat, readFile } from 'node:fs/promises';
|
|
11
12
|
import { randomUUID } from 'node:crypto';
|
|
12
13
|
import { s as shouldEnableOrchestratorTools } from './prompt-BsAZsPbo.mjs';
|
|
13
14
|
import './mcpToolSchemas-CjeTfrAs.mjs';
|
|
@@ -15,19 +16,69 @@ import './index-DTV7drqs.mjs';
|
|
|
15
16
|
import { execSync } from 'node:child_process';
|
|
16
17
|
import 'node:events';
|
|
17
18
|
import 'socket.io-client';
|
|
18
|
-
import './api-
|
|
19
|
+
import './api-L9jLLtI1.mjs';
|
|
19
20
|
import 'tweetnacl';
|
|
20
21
|
import 'ws';
|
|
21
22
|
import 'crypto';
|
|
22
23
|
import '@stablelib/base64';
|
|
23
24
|
import 'node:os';
|
|
24
|
-
import 'node:fs/promises';
|
|
25
25
|
import 'node:fs';
|
|
26
26
|
import 'node:readline';
|
|
27
27
|
import 'expo-server-sdk';
|
|
28
28
|
import 'chalk';
|
|
29
29
|
import './types-BoJh4Qfv.mjs';
|
|
30
30
|
|
|
31
|
+
const MAX_BUG_IMAGES = 10;
|
|
32
|
+
const MAX_BUG_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
33
|
+
const IMAGE_MIME_TYPES = {
|
|
34
|
+
".jpg": "image/jpeg",
|
|
35
|
+
".jpeg": "image/jpeg",
|
|
36
|
+
".png": "image/png"
|
|
37
|
+
};
|
|
38
|
+
function authHeaders(credentials) {
|
|
39
|
+
return { headers: { Authorization: `Bearer ${credentials.token}` }, timeout: 15e3 };
|
|
40
|
+
}
|
|
41
|
+
async function resolveBugId(credentials, reference) {
|
|
42
|
+
const trimmed = reference.trim();
|
|
43
|
+
const displayNumber = trimmed.replace(/^#/, "").match(/^(?:bug-)?(\d+)$/i)?.[1];
|
|
44
|
+
if (!displayNumber) {
|
|
45
|
+
return trimmed;
|
|
46
|
+
}
|
|
47
|
+
const displayId = `BUG-${displayNumber}`;
|
|
48
|
+
const response = await axios.get(
|
|
49
|
+
`${configuration.serverUrl}/v1/bugs`,
|
|
50
|
+
{ params: { query: displayId, limit: 200 }, ...authHeaders(credentials) }
|
|
51
|
+
);
|
|
52
|
+
const match = response.data.bugs.find((bug) => bug.displayId === displayId);
|
|
53
|
+
if (!match) {
|
|
54
|
+
throw new Error(`${displayId} not found on the bug board`);
|
|
55
|
+
}
|
|
56
|
+
return match.id;
|
|
57
|
+
}
|
|
58
|
+
async function attachBugImage(credentials, bugId, filePath) {
|
|
59
|
+
const mimeType = IMAGE_MIME_TYPES[extname(filePath).toLowerCase()];
|
|
60
|
+
if (!mimeType) {
|
|
61
|
+
throw new Error("only .jpg, .jpeg and .png are supported");
|
|
62
|
+
}
|
|
63
|
+
const { size } = await stat(filePath);
|
|
64
|
+
if (size > MAX_BUG_IMAGE_BYTES) {
|
|
65
|
+
throw new Error(`image is ${Math.round(size / 1024 / 1024)}MB, over the 20MB limit`);
|
|
66
|
+
}
|
|
67
|
+
const form = new FormData();
|
|
68
|
+
form.append("file", new Blob([await readFile(filePath)], { type: mimeType }), basename(filePath));
|
|
69
|
+
await axios.post(`${configuration.serverUrl}/v1/bugs/${bugId}/attachments`, form, authHeaders(credentials));
|
|
70
|
+
}
|
|
71
|
+
async function attachImages(credentials, bugId, images, alreadyAttached) {
|
|
72
|
+
const room = Math.max(MAX_BUG_IMAGES - alreadyAttached, 0);
|
|
73
|
+
const attachments = [];
|
|
74
|
+
for (const file of images.slice(0, room)) {
|
|
75
|
+
await attachBugImage(credentials, bugId, file).then(() => attachments.push({ file, ok: true })).catch((error) => attachments.push({ file, ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
76
|
+
}
|
|
77
|
+
for (const file of images.slice(room)) {
|
|
78
|
+
attachments.push({ file, ok: false, error: `skipped \u2014 a bug takes at most ${MAX_BUG_IMAGES} images` });
|
|
79
|
+
}
|
|
80
|
+
return attachments;
|
|
81
|
+
}
|
|
31
82
|
async function submitBug(credentials, input) {
|
|
32
83
|
const response = await axios.post(
|
|
33
84
|
`${configuration.serverUrl}/v1/bugs`,
|
|
@@ -35,9 +86,38 @@ async function submitBug(credentials, input) {
|
|
|
35
86
|
description: input.description,
|
|
36
87
|
...input.visibility ? { visibility: input.visibility } : {}
|
|
37
88
|
},
|
|
38
|
-
|
|
89
|
+
authHeaders(credentials)
|
|
39
90
|
);
|
|
40
|
-
|
|
91
|
+
const bug = response.data.bug;
|
|
92
|
+
const images = input.images ?? [];
|
|
93
|
+
if (!images.length) {
|
|
94
|
+
return bug;
|
|
95
|
+
}
|
|
96
|
+
return { ...bug, attachments: await attachImages(credentials, bug.id, images, 0) };
|
|
97
|
+
}
|
|
98
|
+
async function editBug(credentials, input) {
|
|
99
|
+
const images = input.images ?? [];
|
|
100
|
+
if (!input.description && !images.length) {
|
|
101
|
+
throw new Error("nothing to change \u2014 pass a description, images, or both");
|
|
102
|
+
}
|
|
103
|
+
const bugId = await resolveBugId(credentials, input.bug);
|
|
104
|
+
const bug = input.description ? (await axios.patch(
|
|
105
|
+
`${configuration.serverUrl}/v1/bugs/${bugId}/content`,
|
|
106
|
+
{ description: input.description },
|
|
107
|
+
authHeaders(credentials)
|
|
108
|
+
)).data.bug : (await axios.get(
|
|
109
|
+
`${configuration.serverUrl}/v1/bugs/${bugId}`,
|
|
110
|
+
authHeaders(credentials)
|
|
111
|
+
)).data.bug;
|
|
112
|
+
if (!images.length) {
|
|
113
|
+
return bug;
|
|
114
|
+
}
|
|
115
|
+
return { ...bug, attachments: await attachImages(credentials, bugId, images, bug.attachmentCount ?? 0) };
|
|
116
|
+
}
|
|
117
|
+
async function deleteBug(credentials, reference) {
|
|
118
|
+
const bugId = await resolveBugId(credentials, reference);
|
|
119
|
+
await axios.delete(`${configuration.serverUrl}/v1/bugs/${bugId}`, authHeaders(credentials));
|
|
120
|
+
return { id: bugId };
|
|
41
121
|
}
|
|
42
122
|
|
|
43
123
|
function toToolSuccess(data) {
|
|
@@ -200,7 +280,8 @@ ${result.stderr}`);
|
|
|
200
280
|
title: "Submit Bug",
|
|
201
281
|
inputSchema: {
|
|
202
282
|
description: z.string().describe("What went wrong, what was expected, and how to reproduce it. The title is derived from the first line."),
|
|
203
|
-
visibility: z.enum(["shared", "private"]).optional().describe("shared (default) puts it on the shared board; private keeps it to the owner")
|
|
283
|
+
visibility: z.enum(["shared", "private"]).optional().describe("shared (default) puts it on the shared board; private keeps it to the owner"),
|
|
284
|
+
images: z.array(z.string()).optional().describe("Absolute paths to screenshots on this machine. JPEG and PNG only, up to 10 images, 20MB each.")
|
|
204
285
|
}
|
|
205
286
|
}, async (args) => {
|
|
206
287
|
const credentials = await readCredentials();
|
|
@@ -215,12 +296,52 @@ ${result.stderr}`);
|
|
|
215
296
|
return toToolError(`Failed to submit bug: ${error instanceof Error ? error.message : String(error)}`);
|
|
216
297
|
}
|
|
217
298
|
});
|
|
299
|
+
mcp.registerTool("edit_bug", {
|
|
300
|
+
description: "Change a bug already on the user's Happy bug board: rewrite its description, add screenshots to it, or both. Use when the user wants to correct, expand or illustrate an existing bug.",
|
|
301
|
+
title: "Edit Bug",
|
|
302
|
+
inputSchema: {
|
|
303
|
+
bug: z.string().describe('Which bug, as the user refers to it: "BUG-236", "#236" or "236". An internal bug id also works.'),
|
|
304
|
+
description: z.string().optional().describe("The full replacement description. It replaces the old one outright, so carry over anything still true. Omit to leave the description alone."),
|
|
305
|
+
images: z.array(z.string()).optional().describe("Absolute paths to screenshots on this machine, added to any already on the bug. JPEG and PNG only, 10 per bug in total, 20MB each.")
|
|
306
|
+
}
|
|
307
|
+
}, async (args) => {
|
|
308
|
+
const credentials = await readCredentials();
|
|
309
|
+
if (!credentials) {
|
|
310
|
+
return toToolError("No Happy credentials on this machine.");
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const bug = await editBug(credentials, args);
|
|
314
|
+
logger.debug("[happyMCP] Edited bug:", bug.displayId);
|
|
315
|
+
return toToolSuccess({ ok: true, ...bug });
|
|
316
|
+
} catch (error) {
|
|
317
|
+
return toToolError(`Failed to edit bug: ${error instanceof Error ? error.message : String(error)}`);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
mcp.registerTool("delete_bug", {
|
|
321
|
+
description: "Remove a bug from the user's Happy bug board. The server keeps the row and hides it, so this can be undone by an admin, but it disappears from the board immediately.",
|
|
322
|
+
title: "Delete Bug",
|
|
323
|
+
inputSchema: {
|
|
324
|
+
bug: z.string().describe('Which bug, as the user refers to it: "BUG-236", "#236" or "236". An internal bug id also works.')
|
|
325
|
+
}
|
|
326
|
+
}, async (args) => {
|
|
327
|
+
const credentials = await readCredentials();
|
|
328
|
+
if (!credentials) {
|
|
329
|
+
return toToolError("No Happy credentials on this machine.");
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
const deleted = await deleteBug(credentials, args.bug);
|
|
333
|
+
logger.debug("[happyMCP] Deleted bug:", args.bug);
|
|
334
|
+
return toToolSuccess({ ok: true, ...deleted });
|
|
335
|
+
} catch (error) {
|
|
336
|
+
return toToolError(`Failed to delete bug: ${error instanceof Error ? error.message : String(error)}`);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
218
339
|
return mcp;
|
|
219
340
|
}
|
|
220
341
|
async function startHappyServer(client) {
|
|
221
342
|
const transports = /* @__PURE__ */ new Map();
|
|
222
343
|
const enableOrchestratorTools = shouldEnableOrchestratorTools();
|
|
223
|
-
const toolNames = ["change_title", "preview_html", "device_list", "device_exec", "submit_bug"];
|
|
344
|
+
const toolNames = ["change_title", "preview_html", "device_list", "device_exec", "submit_bug", "edit_bug", "delete_bug"];
|
|
224
345
|
const originalConsoleError = console.error;
|
|
225
346
|
console.error = (...args) => {
|
|
226
347
|
logger.debug("[happyMCP] console.error:", ...args);
|
package/dist/{registerKillSessionHandler-LeIqHfbo.cjs → registerKillSessionHandler-DUrOhiGo.cjs}
RENAMED
|
@@ -7,9 +7,10 @@ var node_http = require('node:http');
|
|
|
7
7
|
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
8
8
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
9
9
|
var z = require('zod');
|
|
10
|
-
var logger = require('./persistence-
|
|
11
|
-
var deviceKeys = require('./deviceKeys-
|
|
10
|
+
var logger = require('./persistence-B_w4o5z-.cjs');
|
|
11
|
+
var deviceKeys = require('./deviceKeys-CzqNNlG1.cjs');
|
|
12
12
|
var axios = require('axios');
|
|
13
|
+
var promises = require('node:fs/promises');
|
|
13
14
|
var node_crypto = require('node:crypto');
|
|
14
15
|
var prompt = require('./prompt-BTWDZZO0.cjs');
|
|
15
16
|
require('./mcpToolSchemas-DK42yoZ_.cjs');
|
|
@@ -17,19 +18,69 @@ require('./index-BeKrqPYR.cjs');
|
|
|
17
18
|
var node_child_process = require('node:child_process');
|
|
18
19
|
require('node:events');
|
|
19
20
|
require('socket.io-client');
|
|
20
|
-
require('./api-
|
|
21
|
+
require('./api-mv48hjhj.cjs');
|
|
21
22
|
require('tweetnacl');
|
|
22
23
|
require('ws');
|
|
23
24
|
require('crypto');
|
|
24
25
|
require('@stablelib/base64');
|
|
25
26
|
require('node:os');
|
|
26
|
-
require('node:fs/promises');
|
|
27
27
|
require('node:fs');
|
|
28
28
|
require('node:readline');
|
|
29
29
|
require('expo-server-sdk');
|
|
30
30
|
require('chalk');
|
|
31
31
|
require('./types-DWeB7aqh.cjs');
|
|
32
32
|
|
|
33
|
+
const MAX_BUG_IMAGES = 10;
|
|
34
|
+
const MAX_BUG_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
35
|
+
const IMAGE_MIME_TYPES = {
|
|
36
|
+
".jpg": "image/jpeg",
|
|
37
|
+
".jpeg": "image/jpeg",
|
|
38
|
+
".png": "image/png"
|
|
39
|
+
};
|
|
40
|
+
function authHeaders(credentials) {
|
|
41
|
+
return { headers: { Authorization: `Bearer ${credentials.token}` }, timeout: 15e3 };
|
|
42
|
+
}
|
|
43
|
+
async function resolveBugId(credentials, reference) {
|
|
44
|
+
const trimmed = reference.trim();
|
|
45
|
+
const displayNumber = trimmed.replace(/^#/, "").match(/^(?:bug-)?(\d+)$/i)?.[1];
|
|
46
|
+
if (!displayNumber) {
|
|
47
|
+
return trimmed;
|
|
48
|
+
}
|
|
49
|
+
const displayId = `BUG-${displayNumber}`;
|
|
50
|
+
const response = await axios.get(
|
|
51
|
+
`${logger.configuration.serverUrl}/v1/bugs`,
|
|
52
|
+
{ params: { query: displayId, limit: 200 }, ...authHeaders(credentials) }
|
|
53
|
+
);
|
|
54
|
+
const match = response.data.bugs.find((bug) => bug.displayId === displayId);
|
|
55
|
+
if (!match) {
|
|
56
|
+
throw new Error(`${displayId} not found on the bug board`);
|
|
57
|
+
}
|
|
58
|
+
return match.id;
|
|
59
|
+
}
|
|
60
|
+
async function attachBugImage(credentials, bugId, filePath) {
|
|
61
|
+
const mimeType = IMAGE_MIME_TYPES[path.extname(filePath).toLowerCase()];
|
|
62
|
+
if (!mimeType) {
|
|
63
|
+
throw new Error("only .jpg, .jpeg and .png are supported");
|
|
64
|
+
}
|
|
65
|
+
const { size } = await promises.stat(filePath);
|
|
66
|
+
if (size > MAX_BUG_IMAGE_BYTES) {
|
|
67
|
+
throw new Error(`image is ${Math.round(size / 1024 / 1024)}MB, over the 20MB limit`);
|
|
68
|
+
}
|
|
69
|
+
const form = new FormData();
|
|
70
|
+
form.append("file", new Blob([await promises.readFile(filePath)], { type: mimeType }), path.basename(filePath));
|
|
71
|
+
await axios.post(`${logger.configuration.serverUrl}/v1/bugs/${bugId}/attachments`, form, authHeaders(credentials));
|
|
72
|
+
}
|
|
73
|
+
async function attachImages(credentials, bugId, images, alreadyAttached) {
|
|
74
|
+
const room = Math.max(MAX_BUG_IMAGES - alreadyAttached, 0);
|
|
75
|
+
const attachments = [];
|
|
76
|
+
for (const file of images.slice(0, room)) {
|
|
77
|
+
await attachBugImage(credentials, bugId, file).then(() => attachments.push({ file, ok: true })).catch((error) => attachments.push({ file, ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
78
|
+
}
|
|
79
|
+
for (const file of images.slice(room)) {
|
|
80
|
+
attachments.push({ file, ok: false, error: `skipped \u2014 a bug takes at most ${MAX_BUG_IMAGES} images` });
|
|
81
|
+
}
|
|
82
|
+
return attachments;
|
|
83
|
+
}
|
|
33
84
|
async function submitBug(credentials, input) {
|
|
34
85
|
const response = await axios.post(
|
|
35
86
|
`${logger.configuration.serverUrl}/v1/bugs`,
|
|
@@ -37,9 +88,38 @@ async function submitBug(credentials, input) {
|
|
|
37
88
|
description: input.description,
|
|
38
89
|
...input.visibility ? { visibility: input.visibility } : {}
|
|
39
90
|
},
|
|
40
|
-
|
|
91
|
+
authHeaders(credentials)
|
|
41
92
|
);
|
|
42
|
-
|
|
93
|
+
const bug = response.data.bug;
|
|
94
|
+
const images = input.images ?? [];
|
|
95
|
+
if (!images.length) {
|
|
96
|
+
return bug;
|
|
97
|
+
}
|
|
98
|
+
return { ...bug, attachments: await attachImages(credentials, bug.id, images, 0) };
|
|
99
|
+
}
|
|
100
|
+
async function editBug(credentials, input) {
|
|
101
|
+
const images = input.images ?? [];
|
|
102
|
+
if (!input.description && !images.length) {
|
|
103
|
+
throw new Error("nothing to change \u2014 pass a description, images, or both");
|
|
104
|
+
}
|
|
105
|
+
const bugId = await resolveBugId(credentials, input.bug);
|
|
106
|
+
const bug = input.description ? (await axios.patch(
|
|
107
|
+
`${logger.configuration.serverUrl}/v1/bugs/${bugId}/content`,
|
|
108
|
+
{ description: input.description },
|
|
109
|
+
authHeaders(credentials)
|
|
110
|
+
)).data.bug : (await axios.get(
|
|
111
|
+
`${logger.configuration.serverUrl}/v1/bugs/${bugId}`,
|
|
112
|
+
authHeaders(credentials)
|
|
113
|
+
)).data.bug;
|
|
114
|
+
if (!images.length) {
|
|
115
|
+
return bug;
|
|
116
|
+
}
|
|
117
|
+
return { ...bug, attachments: await attachImages(credentials, bugId, images, bug.attachmentCount ?? 0) };
|
|
118
|
+
}
|
|
119
|
+
async function deleteBug(credentials, reference) {
|
|
120
|
+
const bugId = await resolveBugId(credentials, reference);
|
|
121
|
+
await axios.delete(`${logger.configuration.serverUrl}/v1/bugs/${bugId}`, authHeaders(credentials));
|
|
122
|
+
return { id: bugId };
|
|
43
123
|
}
|
|
44
124
|
|
|
45
125
|
function toToolSuccess(data) {
|
|
@@ -202,7 +282,8 @@ ${result.stderr}`);
|
|
|
202
282
|
title: "Submit Bug",
|
|
203
283
|
inputSchema: {
|
|
204
284
|
description: z.z.string().describe("What went wrong, what was expected, and how to reproduce it. The title is derived from the first line."),
|
|
205
|
-
visibility: z.z.enum(["shared", "private"]).optional().describe("shared (default) puts it on the shared board; private keeps it to the owner")
|
|
285
|
+
visibility: z.z.enum(["shared", "private"]).optional().describe("shared (default) puts it on the shared board; private keeps it to the owner"),
|
|
286
|
+
images: z.z.array(z.z.string()).optional().describe("Absolute paths to screenshots on this machine. JPEG and PNG only, up to 10 images, 20MB each.")
|
|
206
287
|
}
|
|
207
288
|
}, async (args) => {
|
|
208
289
|
const credentials = await logger.readCredentials();
|
|
@@ -217,12 +298,52 @@ ${result.stderr}`);
|
|
|
217
298
|
return toToolError(`Failed to submit bug: ${error instanceof Error ? error.message : String(error)}`);
|
|
218
299
|
}
|
|
219
300
|
});
|
|
301
|
+
mcp.registerTool("edit_bug", {
|
|
302
|
+
description: "Change a bug already on the user's Happy bug board: rewrite its description, add screenshots to it, or both. Use when the user wants to correct, expand or illustrate an existing bug.",
|
|
303
|
+
title: "Edit Bug",
|
|
304
|
+
inputSchema: {
|
|
305
|
+
bug: z.z.string().describe('Which bug, as the user refers to it: "BUG-236", "#236" or "236". An internal bug id also works.'),
|
|
306
|
+
description: z.z.string().optional().describe("The full replacement description. It replaces the old one outright, so carry over anything still true. Omit to leave the description alone."),
|
|
307
|
+
images: z.z.array(z.z.string()).optional().describe("Absolute paths to screenshots on this machine, added to any already on the bug. JPEG and PNG only, 10 per bug in total, 20MB each.")
|
|
308
|
+
}
|
|
309
|
+
}, async (args) => {
|
|
310
|
+
const credentials = await logger.readCredentials();
|
|
311
|
+
if (!credentials) {
|
|
312
|
+
return toToolError("No Happy credentials on this machine.");
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
const bug = await editBug(credentials, args);
|
|
316
|
+
logger.logger.debug("[happyMCP] Edited bug:", bug.displayId);
|
|
317
|
+
return toToolSuccess({ ok: true, ...bug });
|
|
318
|
+
} catch (error) {
|
|
319
|
+
return toToolError(`Failed to edit bug: ${error instanceof Error ? error.message : String(error)}`);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
mcp.registerTool("delete_bug", {
|
|
323
|
+
description: "Remove a bug from the user's Happy bug board. The server keeps the row and hides it, so this can be undone by an admin, but it disappears from the board immediately.",
|
|
324
|
+
title: "Delete Bug",
|
|
325
|
+
inputSchema: {
|
|
326
|
+
bug: z.z.string().describe('Which bug, as the user refers to it: "BUG-236", "#236" or "236". An internal bug id also works.')
|
|
327
|
+
}
|
|
328
|
+
}, async (args) => {
|
|
329
|
+
const credentials = await logger.readCredentials();
|
|
330
|
+
if (!credentials) {
|
|
331
|
+
return toToolError("No Happy credentials on this machine.");
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
const deleted = await deleteBug(credentials, args.bug);
|
|
335
|
+
logger.logger.debug("[happyMCP] Deleted bug:", args.bug);
|
|
336
|
+
return toToolSuccess({ ok: true, ...deleted });
|
|
337
|
+
} catch (error) {
|
|
338
|
+
return toToolError(`Failed to delete bug: ${error instanceof Error ? error.message : String(error)}`);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
220
341
|
return mcp;
|
|
221
342
|
}
|
|
222
343
|
async function startHappyServer(client) {
|
|
223
344
|
const transports = /* @__PURE__ */ new Map();
|
|
224
345
|
const enableOrchestratorTools = prompt.shouldEnableOrchestratorTools();
|
|
225
|
-
const toolNames = ["change_title", "preview_html", "device_list", "device_exec", "submit_bug"];
|
|
346
|
+
const toolNames = ["change_title", "preview_html", "device_list", "device_exec", "submit_bug", "edit_bug", "delete_bug"];
|
|
226
347
|
const originalConsoleError = console.error;
|
|
227
348
|
console.error = (...args) => {
|
|
228
349
|
logger.logger.debug("[happyMCP] console.error:", ...args);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import os from 'os';
|
|
3
3
|
import * as tmp from 'tmp';
|
|
4
|
-
import { A as ApiClient } from './api-
|
|
5
|
-
import { c as configuration, l as logger, p as packageJson, v as acquireDaemonLock, a as readSettings, i as isDebug, e as encodeBase64, x as writeDaemonState, m as readDaemonState, y as releaseDaemonLock, z as validateProfileForAgent, A as getProfileEnvironmentVariables } from './persistence-
|
|
6
|
-
import { authAndSetupMachineIfNeeded } from './auth-
|
|
4
|
+
import { A as ApiClient } from './api-L9jLLtI1.mjs';
|
|
5
|
+
import { c as configuration, l as logger, p as packageJson, v as acquireDaemonLock, a as readSettings, i as isDebug, e as encodeBase64, x as writeDaemonState, m as readDaemonState, y as releaseDaemonLock, z as validateProfileForAgent, A as getProfileEnvironmentVariables } from './persistence-D2aRTiT1.mjs';
|
|
6
|
+
import { authAndSetupMachineIfNeeded } from './auth-BoWfky2q.mjs';
|
|
7
7
|
import { spawn, execSync, exec } from 'child_process';
|
|
8
|
-
import { getEnvironmentInfo } from './doctor-
|
|
9
|
-
import { s as spawnHappyCLI } from './spawnHappyCLI-
|
|
10
|
-
import { isDaemonRunningCurrentlyInstalledHappyVersion, stopDaemon, cleanupDaemonState } from './controlClient-
|
|
11
|
-
import { a as readCachedDeviceKey, d as deviceExec } from './deviceKeys-
|
|
12
|
-
import { P as PLIST_LABEL } from './install-
|
|
8
|
+
import { getEnvironmentInfo } from './doctor-CXYhUN9A.mjs';
|
|
9
|
+
import { s as spawnHappyCLI } from './spawnHappyCLI-CG_S7LH1.mjs';
|
|
10
|
+
import { isDaemonRunningCurrentlyInstalledHappyVersion, stopDaemon, cleanupDaemonState } from './controlClient-P5wJhu1R.mjs';
|
|
11
|
+
import { a as readCachedDeviceKey, d as deviceExec } from './deviceKeys-tcvwm4KA.mjs';
|
|
12
|
+
import { P as PLIST_LABEL } from './install-Cma2vLWa.mjs';
|
|
13
13
|
import fastify from 'fastify';
|
|
14
14
|
import { createReadStream } from 'node:fs';
|
|
15
15
|
import { stat } from 'node:fs/promises';
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
var fs$1 = require('fs/promises');
|
|
4
4
|
var os = require('os');
|
|
5
5
|
var tmp = require('tmp');
|
|
6
|
-
var api = require('./api-
|
|
7
|
-
var logger = require('./persistence-
|
|
8
|
-
var auth = require('./auth-
|
|
6
|
+
var api = require('./api-mv48hjhj.cjs');
|
|
7
|
+
var logger = require('./persistence-B_w4o5z-.cjs');
|
|
8
|
+
var auth = require('./auth-DfQYhTlg.cjs');
|
|
9
9
|
var child_process = require('child_process');
|
|
10
|
-
var doctor = require('./doctor-
|
|
11
|
-
var spawnHappyCLI = require('./spawnHappyCLI-
|
|
12
|
-
var controlClient = require('./controlClient-
|
|
13
|
-
var deviceKeys = require('./deviceKeys-
|
|
14
|
-
var install = require('./install-
|
|
10
|
+
var doctor = require('./doctor-CBbj6YEl.cjs');
|
|
11
|
+
var spawnHappyCLI = require('./spawnHappyCLI-T9EQFmAR.cjs');
|
|
12
|
+
var controlClient = require('./controlClient-DMEMVw4Y.cjs');
|
|
13
|
+
var deviceKeys = require('./deviceKeys-CzqNNlG1.cjs');
|
|
14
|
+
var install = require('./install-_GiK-K1X.cjs');
|
|
15
15
|
var fastify = require('fastify');
|
|
16
16
|
var fs = require('node:fs');
|
|
17
17
|
var promises = require('node:fs/promises');
|
|
@@ -2,20 +2,20 @@ import os, { homedir } from 'node:os';
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync, unlinkSync, readdirSync } from 'node:fs';
|
|
4
4
|
import { readFile, mkdir, writeFile, stat, copyFile } from 'node:fs/promises';
|
|
5
|
-
import { I as InvalidateSync, k as AsyncLock, d as connectionState, A as ApiClient, r as resolveToolsDir, b as startOfflineReconnection, l as findClaudeProjectId } from './api-
|
|
6
|
-
import { l as logger, i as isDebug, c as configuration, a as readSettings, p as packageJson } from './persistence-
|
|
7
|
-
import { g as getProjectPath, a as claudeLocal, E as ExitCodeError, b as claudeCheckSession, s as systemPrompt } from './claudeLocal-
|
|
5
|
+
import { I as InvalidateSync, k as AsyncLock, d as connectionState, A as ApiClient, r as resolveToolsDir, b as startOfflineReconnection, l as findClaudeProjectId } from './api-L9jLLtI1.mjs';
|
|
6
|
+
import { l as logger, i as isDebug, c as configuration, a as readSettings, p as packageJson } from './persistence-D2aRTiT1.mjs';
|
|
7
|
+
import { g as getProjectPath, a as claudeLocal, E as ExitCodeError, b as claudeCheckSession, s as systemPrompt } from './claudeLocal-CFEXiYts.mjs';
|
|
8
8
|
import { R as RawJSONLinesSchema } from './types-BoJh4Qfv.mjs';
|
|
9
9
|
import { join, resolve } from 'node:path';
|
|
10
10
|
import { d as delay } from './time-DgsBLJA_.mjs';
|
|
11
11
|
import { watch, access } from 'fs/promises';
|
|
12
12
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
13
|
-
import { b as parseSpecialCommand, a as MessageBuffer, M as MessageQueue2, h as hashObject } from './downloadImage-
|
|
13
|
+
import { b as parseSpecialCommand, a as MessageBuffer, M as MessageQueue2, h as hashObject } from './downloadImage-CpnQ3aS1.mjs';
|
|
14
14
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
15
15
|
import { execSync, spawn } from 'node:child_process';
|
|
16
16
|
import { createInterface } from 'node:readline';
|
|
17
17
|
import { fileURLToPath } from 'node:url';
|
|
18
|
-
import { i as isBun } from './spawnHappyCLI-
|
|
18
|
+
import { i as isBun } from './spawnHappyCLI-CG_S7LH1.mjs';
|
|
19
19
|
import { p as projectPath } from './projectPath-BTBIMB57.mjs';
|
|
20
20
|
import 'axios';
|
|
21
21
|
import 'node:events';
|
|
@@ -26,12 +26,12 @@ import 'crypto';
|
|
|
26
26
|
import '@stablelib/base64';
|
|
27
27
|
import 'expo-server-sdk';
|
|
28
28
|
import 'chalk';
|
|
29
|
-
import { a as formatMessageForClaude } from './formatImageMessage-
|
|
29
|
+
import { a as formatMessageForClaude } from './formatImageMessage-ZJZza9-9.mjs';
|
|
30
30
|
import { isDeepStrictEqual } from 'node:util';
|
|
31
|
-
import { i as initialMachineMetadata, s as stopCaffeinate, a as startCaffeinate } from './run-
|
|
32
|
-
import { getEnvironmentInfo } from './doctor-
|
|
33
|
-
import { notifyDaemonSessionStarted } from './controlClient-
|
|
34
|
-
import { c as createMcpContext, r as registerKillSessionHandler, d as detectGitWorktree } from './registerKillSessionHandler-
|
|
31
|
+
import { i as initialMachineMetadata, s as stopCaffeinate, a as startCaffeinate } from './run-D6oXm1Jk.mjs';
|
|
32
|
+
import { getEnvironmentInfo } from './doctor-CXYhUN9A.mjs';
|
|
33
|
+
import { notifyDaemonSessionStarted } from './controlClient-P5wJhu1R.mjs';
|
|
34
|
+
import { c as createMcpContext, r as registerKillSessionHandler, d as detectGitWorktree } from './registerKillSessionHandler-AcpB6OSk.mjs';
|
|
35
35
|
import { createServer } from 'node:http';
|
|
36
36
|
import 'zod';
|
|
37
37
|
import './index-DTV7drqs.mjs';
|
|
@@ -40,7 +40,7 @@ import 'child_process';
|
|
|
40
40
|
import 'util';
|
|
41
41
|
import 'path';
|
|
42
42
|
import 'node:module';
|
|
43
|
-
import './sessionKeyCache-
|
|
43
|
+
import './sessionKeyCache-CEJH5cHj.mjs';
|
|
44
44
|
import 'fs';
|
|
45
45
|
import './prompt-BsAZsPbo.mjs';
|
|
46
46
|
import './trimIdent-BAjmv_TG.mjs';
|
|
@@ -48,12 +48,12 @@ import './common-BdNgghUJ.mjs';
|
|
|
48
48
|
import 'url';
|
|
49
49
|
import 'os';
|
|
50
50
|
import 'tmp';
|
|
51
|
-
import './auth-
|
|
51
|
+
import './auth-BoWfky2q.mjs';
|
|
52
52
|
import 'qrcode-terminal';
|
|
53
|
-
import './browser-
|
|
53
|
+
import './browser-D9jMe1me.mjs';
|
|
54
54
|
import 'open';
|
|
55
|
-
import './deviceKeys-
|
|
56
|
-
import './install-
|
|
55
|
+
import './deviceKeys-tcvwm4KA.mjs';
|
|
56
|
+
import './install-Cma2vLWa.mjs';
|
|
57
57
|
import 'fastify';
|
|
58
58
|
import 'fastify-type-provider-zod';
|
|
59
59
|
import './doctor-ON7pN5G5.mjs';
|