@hubspot/cli 8.4.0 → 8.5.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/migrate.js +3 -3
- package/bin/cli.js +3 -0
- package/commands/app/migrate.js +4 -4
- package/commands/getStarted.js +2 -2
- package/commands/project/add.js +3 -3
- package/commands/project/create.js +10 -7
- package/commands/project/delete.js +2 -2
- package/commands/project/deploy.js +4 -3
- package/commands/project/dev/index.js +5 -4
- package/commands/project/info.js +2 -2
- package/commands/project/migrate.js +5 -5
- package/commands/project/profile/add.js +2 -2
- package/commands/project/profile/delete.js +2 -2
- package/commands/project/upload.js +3 -3
- package/commands/project/validate.js +2 -2
- package/commands/project/watch.js +2 -2
- package/commands/project.js +6 -3
- package/commands/testAccount/create.js +4 -4
- package/lang/en.d.ts +11 -0
- package/lang/en.js +16 -5
- package/lib/app/migrate.js +7 -0
- package/lib/constants.d.ts +0 -1
- package/lib/constants.js +0 -1
- package/lib/doctor/Doctor.js +2 -2
- package/lib/getStartedV2Actions.js +2 -2
- package/lib/hasFeature.js +1 -2
- package/lib/middleware/autoUpdateMiddleware.js +6 -3
- package/lib/projects/ProjectLogsManager.js +6 -3
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/legacy.js +2 -2
- package/lib/projects/create/v2.js +3 -4
- package/lib/projects/delete.js +2 -2
- package/lib/projects/deploy.d.ts +1 -1
- package/lib/projects/deploy.js +2 -2
- package/lib/projects/upload.js +22 -3
- package/lib/projects/workspaces.d.ts +42 -0
- package/lib/projects/workspaces.js +350 -0
- package/lib/prompts/projectsLogsPrompt.js +3 -0
- package/lib/theme/cmsDevServerProcess.js +1 -1
- package/mcp-server/Tool.d.ts +15 -0
- package/mcp-server/Tool.js +53 -0
- package/mcp-server/server.js +5 -3
- package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +4 -2
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +8 -6
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +4 -2
- package/mcp-server/tools/cms/HsCreateModuleTool.js +8 -6
- package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +4 -2
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -6
- package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +4 -2
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +8 -6
- package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +4 -2
- package/mcp-server/tools/cms/HsListFunctionsTool.js +8 -6
- package/mcp-server/tools/cms/HsListTool.d.ts +4 -2
- package/mcp-server/tools/cms/HsListTool.js +8 -6
- package/mcp-server/tools/index.d.ts +3 -2
- package/mcp-server/tools/index.js +22 -22
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +6 -4
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +8 -6
- package/mcp-server/tools/project/CreateProjectTool.d.ts +6 -4
- package/mcp-server/tools/project/CreateProjectTool.js +9 -7
- package/mcp-server/tools/project/CreateTestAccountTool.d.ts +4 -2
- package/mcp-server/tools/project/CreateTestAccountTool.js +20 -8
- package/mcp-server/tools/project/DeployProjectTool.d.ts +4 -2
- package/mcp-server/tools/project/DeployProjectTool.js +4 -6
- package/mcp-server/tools/project/DocFetchTool.d.ts +4 -2
- package/mcp-server/tools/project/DocFetchTool.js +8 -6
- package/mcp-server/tools/project/DocsSearchTool.d.ts +9 -3
- package/mcp-server/tools/project/DocsSearchTool.js +32 -9
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +4 -2
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +8 -6
- package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +4 -2
- package/mcp-server/tools/project/GetApplicationInfoTool.js +8 -6
- package/mcp-server/tools/project/GetBuildLogsTool.d.ts +4 -2
- package/mcp-server/tools/project/GetBuildLogsTool.js +8 -6
- package/mcp-server/tools/project/GetBuildStatusTool.d.ts +4 -2
- package/mcp-server/tools/project/GetBuildStatusTool.js +8 -6
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -2
- package/mcp-server/tools/project/GetConfigValuesTool.js +12 -7
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +4 -2
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +4 -6
- package/mcp-server/tools/project/UploadProjectTools.d.ts +4 -2
- package/mcp-server/tools/project/UploadProjectTools.js +9 -7
- package/mcp-server/tools/project/ValidateProjectTool.d.ts +4 -2
- package/mcp-server/tools/project/ValidateProjectTool.js +8 -6
- package/mcp-server/tools/project/constants.d.ts +2 -2
- package/mcp-server/types.d.ts +0 -7
- package/mcp-server/types.js +1 -13
- package/mcp-server/utils/logger.d.ts +10 -0
- package/mcp-server/utils/logger.js +29 -0
- package/mcp-server/utils/toolUsageTracking.js +0 -2
- package/package.json +10 -10
- package/lib/projects/platformVersion.d.ts +0 -9
- package/lib/projects/platformVersion.js +0 -39
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
import { shouldIgnoreFile } from '@hubspot/local-dev-lib/ignoreRules';
|
|
5
|
+
import { getPackableFiles, } from '@hubspot/project-parsing-lib/workspaces';
|
|
6
|
+
import { uiLogger } from '../ui/logger.js';
|
|
7
|
+
import { lib } from '../../lang/en.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generates a short hash of the input string for use in workspace paths.
|
|
10
|
+
* Uses SHA256 truncated to 8 hex characters (4 billion possibilities).
|
|
11
|
+
*/
|
|
12
|
+
export function shortHash(input) {
|
|
13
|
+
return crypto.createHash('sha256').update(input).digest('hex').slice(0, 8);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Determines the archive path for an external workspace or file: dependency.
|
|
17
|
+
* Produces `_workspaces/<basename>-<hash>` with no subdirectory.
|
|
18
|
+
* The hash prevents collisions between different directories with the same basename.
|
|
19
|
+
*/
|
|
20
|
+
export function computeExternalArchivePath(absolutePath) {
|
|
21
|
+
const resolved = path.resolve(absolutePath);
|
|
22
|
+
const name = path.basename(resolved);
|
|
23
|
+
return path.join('_workspaces', `${name}-${shortHash(resolved)}`);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns true if dir is inside srcDir (i.e. it will already be included
|
|
27
|
+
* in the archive from the srcDir walk and must not be copied again).
|
|
28
|
+
*/
|
|
29
|
+
function isInsideSrcDir(dir, srcDir) {
|
|
30
|
+
const rel = path.relative(path.resolve(srcDir), path.resolve(dir));
|
|
31
|
+
return !rel.startsWith('..') && !path.isAbsolute(rel);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a file filter function for workspace archiving.
|
|
35
|
+
* Filters files based on packable files list and ignore rules.
|
|
36
|
+
*/
|
|
37
|
+
function createWorkspaceFileFilter(packableFiles) {
|
|
38
|
+
return (file) => {
|
|
39
|
+
if (packableFiles.size > 0 && !packableFiles.has(file.name)) {
|
|
40
|
+
uiLogger.debug(lib.projectUpload.handleProjectUpload.fileFiltered(file.name));
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const ignored = shouldIgnoreFile(file.name, true);
|
|
44
|
+
if (ignored) {
|
|
45
|
+
uiLogger.debug(lib.projectUpload.handleProjectUpload.fileFiltered(file.name));
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return file;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Archives workspace directories and returns mapping information.
|
|
53
|
+
*
|
|
54
|
+
* Internal workspaces (inside srcDir) are not archived — they are already
|
|
55
|
+
* included via the srcDir walk. Their relative paths (from the package.json
|
|
56
|
+
* directory to the workspace directory) are stored directly in the entries.
|
|
57
|
+
*
|
|
58
|
+
* External workspaces (outside srcDir) are copied to `_workspaces/<name>-<hash>`
|
|
59
|
+
* and their relative archive paths (e.g. `../_workspaces/<name>-<hash>`) are stored.
|
|
60
|
+
*/
|
|
61
|
+
async function archiveWorkspaceDirectories(archive, srcDir, workspaceMappings) {
|
|
62
|
+
const externalArchivePaths = new Map(); // resolvedDir -> archivePath
|
|
63
|
+
const archivePathToDir = new Map(); // archivePath -> resolvedDir (collision detection)
|
|
64
|
+
const packageWorkspaceEntries = new Map();
|
|
65
|
+
const externalsToArchive = [];
|
|
66
|
+
for (const mapping of workspaceMappings) {
|
|
67
|
+
const { workspaceDir, sourcePackageJsonPath } = mapping;
|
|
68
|
+
if (!packageWorkspaceEntries.has(sourcePackageJsonPath)) {
|
|
69
|
+
packageWorkspaceEntries.set(sourcePackageJsonPath, []);
|
|
70
|
+
}
|
|
71
|
+
if (isInsideSrcDir(workspaceDir, srcDir)) {
|
|
72
|
+
// Internal: already in archive from srcDir walk.
|
|
73
|
+
// Store the relative path from the package.json directory so npm can resolve it.
|
|
74
|
+
const relPath = path.relative(path.dirname(sourcePackageJsonPath), path.resolve(workspaceDir));
|
|
75
|
+
packageWorkspaceEntries.get(sourcePackageJsonPath).push(relPath);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// External: archive to _workspaces/<name>-<hash>.
|
|
79
|
+
const archivePath = computeExternalArchivePath(workspaceDir);
|
|
80
|
+
const resolvedDir = path.resolve(workspaceDir);
|
|
81
|
+
// Detect hash collisions (different dirs mapping to the same archive path)
|
|
82
|
+
const existing = archivePathToDir.get(archivePath);
|
|
83
|
+
if (existing && existing !== resolvedDir) {
|
|
84
|
+
throw new Error(lib.projectUpload.handleProjectUpload.workspaceCollision(archivePath, workspaceDir, existing));
|
|
85
|
+
}
|
|
86
|
+
if (!externalArchivePaths.has(resolvedDir)) {
|
|
87
|
+
externalArchivePaths.set(resolvedDir, archivePath);
|
|
88
|
+
archivePathToDir.set(archivePath, resolvedDir);
|
|
89
|
+
externalsToArchive.push({ dir: workspaceDir, archivePath });
|
|
90
|
+
}
|
|
91
|
+
const relPkgJsonDir = path.relative(srcDir, path.dirname(sourcePackageJsonPath));
|
|
92
|
+
const relativeEntry = path.relative(relPkgJsonDir, archivePath);
|
|
93
|
+
packageWorkspaceEntries.get(sourcePackageJsonPath).push(relativeEntry);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Fetch packable files in parallel (I/O optimization)
|
|
97
|
+
const withPackableFiles = await Promise.all(externalsToArchive.map(async (item) => ({
|
|
98
|
+
...item,
|
|
99
|
+
packableFiles: await getPackableFiles(item.dir),
|
|
100
|
+
})));
|
|
101
|
+
// Archive directories sequentially (archiver requires sequential operations)
|
|
102
|
+
for (const { dir, archivePath, packableFiles } of withPackableFiles) {
|
|
103
|
+
uiLogger.log(lib.projectUpload.handleProjectUpload.workspaceIncluded(dir, archivePath));
|
|
104
|
+
archive.directory(dir, archivePath, createWorkspaceFileFilter(packableFiles));
|
|
105
|
+
}
|
|
106
|
+
return { externalArchivePaths, packageWorkspaceEntries };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Archives file: dependencies and returns mapping information.
|
|
110
|
+
*
|
|
111
|
+
* Internal file: dependencies (inside srcDir) are skipped — their original
|
|
112
|
+
* `file:` references in package.json remain valid after upload.
|
|
113
|
+
*
|
|
114
|
+
* External file: dependencies are archived to `_workspaces/<name>-<hash>`
|
|
115
|
+
* and tracked in the returned map so package.json can be rewritten.
|
|
116
|
+
*/
|
|
117
|
+
async function archiveFileDependencies(archive, srcDir, fileDependencyMappings, externalArchivePaths) {
|
|
118
|
+
const packageFileDeps = new Map();
|
|
119
|
+
const toArchive = [];
|
|
120
|
+
for (const mapping of fileDependencyMappings) {
|
|
121
|
+
const { packageName, localPath, sourcePackageJsonPath } = mapping;
|
|
122
|
+
if (isInsideSrcDir(localPath, srcDir)) {
|
|
123
|
+
// Internal: original file: reference stays unchanged, nothing to do
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
// External: archive to _workspaces/<name>-<hash>
|
|
127
|
+
const archivePath = computeExternalArchivePath(localPath);
|
|
128
|
+
const resolvedPath = path.resolve(localPath);
|
|
129
|
+
if (!packageFileDeps.has(sourcePackageJsonPath)) {
|
|
130
|
+
packageFileDeps.set(sourcePackageJsonPath, new Map());
|
|
131
|
+
}
|
|
132
|
+
const relPkgJsonDir = path.relative(srcDir, path.dirname(sourcePackageJsonPath));
|
|
133
|
+
const relativeArchivePath = path.relative(relPkgJsonDir, archivePath);
|
|
134
|
+
packageFileDeps
|
|
135
|
+
.get(sourcePackageJsonPath)
|
|
136
|
+
.set(packageName, relativeArchivePath);
|
|
137
|
+
// Only archive each unique path once
|
|
138
|
+
if (!externalArchivePaths.has(resolvedPath)) {
|
|
139
|
+
externalArchivePaths.set(resolvedPath, archivePath);
|
|
140
|
+
toArchive.push({ localPath, archivePath, packageName });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Fetch packable files in parallel (I/O optimization)
|
|
144
|
+
const withPackableFiles = await Promise.all(toArchive.map(async (item) => ({
|
|
145
|
+
...item,
|
|
146
|
+
packableFiles: await getPackableFiles(item.localPath),
|
|
147
|
+
})));
|
|
148
|
+
// Archive directories sequentially (archiver requires sequential operations)
|
|
149
|
+
for (const { localPath, archivePath, packageName, packableFiles, } of withPackableFiles) {
|
|
150
|
+
uiLogger.log(lib.projectUpload.handleProjectUpload.fileDependencyIncluded(packageName, localPath, archivePath));
|
|
151
|
+
archive.directory(localPath, archivePath, createWorkspaceFileFilter(packableFiles));
|
|
152
|
+
}
|
|
153
|
+
return packageFileDeps;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Updates package.json files in the archive to reflect new workspace and file: dependency paths.
|
|
157
|
+
*
|
|
158
|
+
* Workspace entries in packageWorkspaces are already in final form:
|
|
159
|
+
* - Internal workspaces: relative paths (e.g. "../packages/utils")
|
|
160
|
+
* - External workspaces: relative paths (e.g. "../_workspaces/logger-abc")
|
|
161
|
+
*
|
|
162
|
+
* Only external file: dependencies appear in packageFileDeps; internal ones
|
|
163
|
+
* keep their original file: references and are left untouched.
|
|
164
|
+
*/
|
|
165
|
+
export async function updatePackageJsonInArchive(archive, srcDir, packageWorkspaces, packageFileDeps) {
|
|
166
|
+
// Collect all package.json paths that need updating
|
|
167
|
+
const allPackageJsonPaths = new Set([
|
|
168
|
+
...packageWorkspaces.keys(),
|
|
169
|
+
...packageFileDeps.keys(),
|
|
170
|
+
]);
|
|
171
|
+
for (const packageJsonPath of allPackageJsonPaths) {
|
|
172
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const relativePackageJsonPath = path.relative(srcDir, packageJsonPath);
|
|
176
|
+
let rawContent;
|
|
177
|
+
try {
|
|
178
|
+
rawContent = fs.readFileSync(packageJsonPath, 'utf8');
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
let packageJson;
|
|
184
|
+
try {
|
|
185
|
+
packageJson = JSON.parse(rawContent);
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
uiLogger.warn(lib.projectUpload.handleProjectUpload.malformedPackageJson(packageJsonPath, e instanceof Error ? e.message : String(e)));
|
|
189
|
+
archive.append(rawContent, { name: relativePackageJsonPath });
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
let modified = false;
|
|
193
|
+
// Update workspaces field — entries are already in their final form
|
|
194
|
+
const workspaceEntries = packageWorkspaces.get(packageJsonPath);
|
|
195
|
+
if (workspaceEntries && packageJson.workspaces) {
|
|
196
|
+
packageJson.workspaces = workspaceEntries;
|
|
197
|
+
modified = true;
|
|
198
|
+
uiLogger.debug(lib.projectUpload.handleProjectUpload.updatingPackageJsonWorkspaces(relativePackageJsonPath));
|
|
199
|
+
uiLogger.debug(lib.projectUpload.handleProjectUpload.updatedWorkspaces(workspaceEntries.join(', ')));
|
|
200
|
+
}
|
|
201
|
+
// Update external file: dependencies; internal ones are left untouched
|
|
202
|
+
const fileDeps = packageFileDeps.get(packageJsonPath);
|
|
203
|
+
if (fileDeps && fileDeps.size > 0 && packageJson.dependencies) {
|
|
204
|
+
for (const [packageName, archivePath] of fileDeps.entries()) {
|
|
205
|
+
if (packageJson.dependencies[packageName]?.startsWith('file:')) {
|
|
206
|
+
packageJson.dependencies[packageName] = `file:${archivePath}`;
|
|
207
|
+
modified = true;
|
|
208
|
+
uiLogger.debug(lib.projectUpload.handleProjectUpload.updatedFileDependency(packageName, archivePath));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
archive.append(modified ? JSON.stringify(packageJson, null, 2) : rawContent, { name: relativePackageJsonPath });
|
|
213
|
+
}
|
|
214
|
+
// Ensure all append operations are queued before finalize is called
|
|
215
|
+
// Use setImmediate to yield control and let archiver process the queue
|
|
216
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
217
|
+
}
|
|
218
|
+
export function rewriteLockfileForExternalDeps(lockfileContent, pathMappings) {
|
|
219
|
+
if (pathMappings.length === 0) {
|
|
220
|
+
return lockfileContent;
|
|
221
|
+
}
|
|
222
|
+
const packages = lockfileContent.packages;
|
|
223
|
+
if (!packages) {
|
|
224
|
+
return lockfileContent;
|
|
225
|
+
}
|
|
226
|
+
const newPackages = {};
|
|
227
|
+
for (const [key, value] of Object.entries(packages)) {
|
|
228
|
+
const mapping = pathMappings.find(m => m.oldPath === key);
|
|
229
|
+
newPackages[mapping ? mapping.newPath : key] = value;
|
|
230
|
+
}
|
|
231
|
+
for (const [key, value] of Object.entries(newPackages)) {
|
|
232
|
+
if (key.startsWith('node_modules/') &&
|
|
233
|
+
typeof value === 'object' &&
|
|
234
|
+
value !== null) {
|
|
235
|
+
const entry = value;
|
|
236
|
+
if (entry.link === true && typeof entry.resolved === 'string') {
|
|
237
|
+
const mapping = pathMappings.find(m => m.oldPath === entry.resolved);
|
|
238
|
+
if (mapping) {
|
|
239
|
+
newPackages[key] = { ...entry, resolved: mapping.newPath };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const rootEntry = newPackages[''];
|
|
245
|
+
if (rootEntry && typeof rootEntry === 'object' && rootEntry !== null) {
|
|
246
|
+
const root = rootEntry;
|
|
247
|
+
if (Array.isArray(root.workspaces)) {
|
|
248
|
+
newPackages[''] = {
|
|
249
|
+
...root,
|
|
250
|
+
workspaces: root.workspaces.map((ws) => {
|
|
251
|
+
if (typeof ws !== 'string')
|
|
252
|
+
return ws;
|
|
253
|
+
const mapping = pathMappings.find(m => m.oldPath === ws);
|
|
254
|
+
return mapping ? mapping.newPath : ws;
|
|
255
|
+
}),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { ...lockfileContent, packages: newPackages };
|
|
260
|
+
}
|
|
261
|
+
export function getPackageJsonPathsToUpdate(srcDir, workspaceMappings, fileDependencyMappings) {
|
|
262
|
+
const paths = new Set();
|
|
263
|
+
for (const { sourcePackageJsonPath } of workspaceMappings) {
|
|
264
|
+
paths.add(path.relative(srcDir, sourcePackageJsonPath));
|
|
265
|
+
}
|
|
266
|
+
for (const { localPath, sourcePackageJsonPath } of fileDependencyMappings) {
|
|
267
|
+
if (!isInsideSrcDir(localPath, srcDir)) {
|
|
268
|
+
paths.add(path.relative(srcDir, sourcePackageJsonPath));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return paths;
|
|
272
|
+
}
|
|
273
|
+
function getDirsWithExternalDeps(srcDir, workspaceMappings, fileDependencyMappings) {
|
|
274
|
+
const dirs = new Set();
|
|
275
|
+
for (const { workspaceDir, sourcePackageJsonPath } of workspaceMappings) {
|
|
276
|
+
if (!isInsideSrcDir(workspaceDir, srcDir)) {
|
|
277
|
+
dirs.add(path.dirname(sourcePackageJsonPath));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
for (const { localPath, sourcePackageJsonPath } of fileDependencyMappings) {
|
|
281
|
+
if (!isInsideSrcDir(localPath, srcDir)) {
|
|
282
|
+
dirs.add(path.dirname(sourcePackageJsonPath));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return dirs;
|
|
286
|
+
}
|
|
287
|
+
export function getLockfilePathsToUpdate(srcDir, workspaceMappings, fileDependencyMappings) {
|
|
288
|
+
const dirsWithExternalDeps = getDirsWithExternalDeps(srcDir, workspaceMappings, fileDependencyMappings);
|
|
289
|
+
const paths = new Set();
|
|
290
|
+
for (const dir of dirsWithExternalDeps) {
|
|
291
|
+
const lockfilePath = path.join(dir, 'package-lock.json');
|
|
292
|
+
if (fs.existsSync(lockfilePath)) {
|
|
293
|
+
paths.add(path.relative(srcDir, lockfilePath));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return paths;
|
|
297
|
+
}
|
|
298
|
+
async function rewriteLockfilesInArchive(archive, srcDir, externalArchivePaths, dirsWithExternalDeps) {
|
|
299
|
+
if (externalArchivePaths.size === 0)
|
|
300
|
+
return;
|
|
301
|
+
for (const dir of dirsWithExternalDeps) {
|
|
302
|
+
const lockfilePath = path.join(dir, 'package-lock.json');
|
|
303
|
+
if (!fs.existsSync(lockfilePath))
|
|
304
|
+
continue;
|
|
305
|
+
let rawContent;
|
|
306
|
+
try {
|
|
307
|
+
rawContent = fs.readFileSync(lockfilePath, 'utf8');
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
let lockfileContent;
|
|
313
|
+
try {
|
|
314
|
+
lockfileContent = JSON.parse(rawContent);
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
const pathMappings = [];
|
|
320
|
+
for (const [absoluteExternalPath, archivePath] of externalArchivePaths) {
|
|
321
|
+
pathMappings.push({
|
|
322
|
+
oldPath: path.relative(dir, absoluteExternalPath),
|
|
323
|
+
newPath: path.relative(dir, path.join(srcDir, archivePath)),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
const rewritten = rewriteLockfileForExternalDeps(lockfileContent, pathMappings);
|
|
327
|
+
const relativeLockfilePath = path.relative(srcDir, lockfilePath);
|
|
328
|
+
uiLogger.debug(lib.projectUpload.handleProjectUpload.updatingLockfile(relativeLockfilePath));
|
|
329
|
+
archive.append(JSON.stringify(rewritten, null, 2), {
|
|
330
|
+
name: relativeLockfilePath,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Main orchestration function that handles archiving of workspaces and file dependencies.
|
|
337
|
+
* This is the clean integration point for upload.ts.
|
|
338
|
+
*/
|
|
339
|
+
export async function archiveWorkspacesAndDependencies(archive, srcDir, projectDir, workspaceMappings, fileDependencyMappings) {
|
|
340
|
+
// Archive workspace directories (internal ones are skipped, externals are copied)
|
|
341
|
+
const { externalArchivePaths, packageWorkspaceEntries } = await archiveWorkspaceDirectories(archive, srcDir, workspaceMappings);
|
|
342
|
+
// Archive external file: dependencies (internals are skipped)
|
|
343
|
+
const packageFileDeps = await archiveFileDependencies(archive, srcDir, fileDependencyMappings, externalArchivePaths);
|
|
344
|
+
// Update package.json files with new paths
|
|
345
|
+
await updatePackageJsonInArchive(archive, srcDir, packageWorkspaceEntries, packageFileDeps);
|
|
346
|
+
// Rewrite lock files to point to archive paths for external deps
|
|
347
|
+
const dirsWithExternalDeps = getDirsWithExternalDeps(srcDir, workspaceMappings, fileDependencyMappings);
|
|
348
|
+
await rewriteLockfilesInArchive(archive, srcDir, externalArchivePaths, dirsWithExternalDeps);
|
|
349
|
+
return { packageWorkspaces: packageWorkspaceEntries, packageFileDeps };
|
|
350
|
+
}
|
|
@@ -4,6 +4,9 @@ export async function projectLogsPrompt({ functionChoices, promptOptions, projec
|
|
|
4
4
|
if (!functionChoices) {
|
|
5
5
|
return {};
|
|
6
6
|
}
|
|
7
|
+
if (promptOptions?.function) {
|
|
8
|
+
return { functionName: promptOptions.function };
|
|
9
|
+
}
|
|
7
10
|
if (functionChoices.length === 1) {
|
|
8
11
|
return { functionName: functionChoices[0] };
|
|
9
12
|
}
|
|
@@ -10,7 +10,7 @@ import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
11
|
const __dirname = path.dirname(__filename);
|
|
12
12
|
// cms-dev-server version to install to isolated cache
|
|
13
|
-
const TARGET_CMS_DEV_SERVER_VERSION = '1.2.
|
|
13
|
+
const TARGET_CMS_DEV_SERVER_VERSION = '1.2.26';
|
|
14
14
|
/**
|
|
15
15
|
* Ensures cms-dev-server is installed in an isolated cache directory.
|
|
16
16
|
* This prevents React version conflicts with the CLI.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { McpLogger } from './utils/logger.js';
|
|
3
|
+
import { TextContentResponse } from './types.js';
|
|
4
|
+
export declare class Tool<InputSchema> {
|
|
5
|
+
protected mcpServer: McpServer;
|
|
6
|
+
protected logger: McpLogger;
|
|
7
|
+
protected toolName: string;
|
|
8
|
+
constructor(mcpServer: McpServer, logger: McpLogger, toolName: string);
|
|
9
|
+
register(): RegisteredTool;
|
|
10
|
+
handler(input: InputSchema): TextContentResponse | Promise<TextContentResponse>;
|
|
11
|
+
protected getTrackingMeta(input: InputSchema): {
|
|
12
|
+
[key: string]: string;
|
|
13
|
+
} | undefined;
|
|
14
|
+
protected wrappedHandler(input: InputSchema): Promise<TextContentResponse>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { formatTextContents } from './utils/content.js';
|
|
2
|
+
import { getErrorMessage } from '../lib/errorHandlers/index.js';
|
|
3
|
+
import { trackToolUsage } from './utils/toolUsageTracking.js';
|
|
4
|
+
export class Tool {
|
|
5
|
+
mcpServer;
|
|
6
|
+
logger;
|
|
7
|
+
toolName;
|
|
8
|
+
constructor(mcpServer, logger, toolName) {
|
|
9
|
+
this.mcpServer = mcpServer;
|
|
10
|
+
this.logger = logger;
|
|
11
|
+
this.toolName = toolName;
|
|
12
|
+
}
|
|
13
|
+
register() {
|
|
14
|
+
throw new Error('Must implement register');
|
|
15
|
+
}
|
|
16
|
+
handler(
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
18
|
+
input) {
|
|
19
|
+
throw new Error('Must implement handler');
|
|
20
|
+
}
|
|
21
|
+
getTrackingMeta(
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
|
+
input) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
async wrappedHandler(input) {
|
|
27
|
+
const startTime = Date.now();
|
|
28
|
+
try {
|
|
29
|
+
// `input` is logged unredacted. Tool input schemas MUST NOT include
|
|
30
|
+
// credentials or other sensitive values, since MCP clients (Claude
|
|
31
|
+
// Desktop, Inspector, etc.) will display these logs.
|
|
32
|
+
this.logger.debug(this.toolName, {
|
|
33
|
+
message: 'Tool invoked',
|
|
34
|
+
args: input,
|
|
35
|
+
});
|
|
36
|
+
await trackToolUsage(this.toolName, this.getTrackingMeta(input));
|
|
37
|
+
const result = await this.handler(input);
|
|
38
|
+
this.logger.debug(this.toolName, {
|
|
39
|
+
message: 'Tool completed',
|
|
40
|
+
durationMs: Date.now() - startTime,
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
this.logger.error(this.toolName, {
|
|
46
|
+
message: 'Tool failed',
|
|
47
|
+
error: error instanceof Error ? error.message : String(error),
|
|
48
|
+
durationMs: Date.now() - startTime,
|
|
49
|
+
});
|
|
50
|
+
return formatTextContents(getErrorMessage(error));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
package/mcp-server/server.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { registerProjectTools, registerCmsTools } from './tools/index.js';
|
|
4
|
+
import { McpLogger } from './utils/logger.js';
|
|
4
5
|
const server = new McpServer({
|
|
5
6
|
name: 'HubSpot CLI MCP Server',
|
|
6
7
|
version: '0.0.1',
|
|
7
8
|
description: 'Helps perform tasks for local development of HubSpot projects.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
}, { capabilities: { logging: {} } });
|
|
10
|
+
const logger = new McpLogger(server);
|
|
11
|
+
registerProjectTools(server, logger);
|
|
12
|
+
registerCmsTools(server, logger);
|
|
11
13
|
// Start receiving messages on stdin and sending messages on stdout
|
|
12
14
|
const transport = new StdioServerTransport();
|
|
13
15
|
server.connect(transport);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { TextContentResponse
|
|
1
|
+
import { TextContentResponse } from '../../types.js';
|
|
2
|
+
import { Tool } from '../../Tool.js';
|
|
2
3
|
import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { McpLogger } from '../../utils/logger.js';
|
|
3
5
|
import { z } from 'zod';
|
|
4
6
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
5
7
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
@@ -17,7 +19,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
17
19
|
}, z.core.$strip>;
|
|
18
20
|
export type HsCreateFunctionInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
19
21
|
export declare class HsCreateFunctionTool extends Tool<HsCreateFunctionInputSchema> {
|
|
20
|
-
constructor(mcpServer: McpServer);
|
|
22
|
+
constructor(mcpServer: McpServer, logger: McpLogger);
|
|
21
23
|
handler({ dest, functionsFolder, filename, endpointMethod, endpointPath, absoluteCurrentWorkingDirectory, }: HsCreateFunctionInputSchema): Promise<TextContentResponse>;
|
|
22
24
|
register(): RegisteredTool;
|
|
23
25
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Tool } from '../../
|
|
1
|
+
import { Tool } from '../../Tool.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
4
|
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
|
-
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
6
|
import { addFlag } from '../../utils/command.js';
|
|
8
7
|
import { HTTP_METHODS } from '../../../types/Cms.js';
|
|
9
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
@@ -35,12 +34,11 @@ const inputSchema = {
|
|
|
35
34
|
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
36
35
|
const toolName = 'create-cms-function';
|
|
37
36
|
export class HsCreateFunctionTool extends Tool {
|
|
38
|
-
constructor(mcpServer) {
|
|
39
|
-
super(mcpServer);
|
|
37
|
+
constructor(mcpServer, logger) {
|
|
38
|
+
super(mcpServer, logger, toolName);
|
|
40
39
|
}
|
|
41
40
|
async handler({ dest, functionsFolder, filename, endpointMethod, endpointPath, absoluteCurrentWorkingDirectory, }) {
|
|
42
41
|
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
43
|
-
await trackToolUsage(toolName);
|
|
44
42
|
const content = [];
|
|
45
43
|
// Require functions folder
|
|
46
44
|
if (!functionsFolder) {
|
|
@@ -86,6 +84,10 @@ export class HsCreateFunctionTool extends Tool {
|
|
|
86
84
|
return formatTextContents(stdout, stderr);
|
|
87
85
|
}
|
|
88
86
|
catch (error) {
|
|
87
|
+
this.logger.debug(toolName, {
|
|
88
|
+
message: 'Handler caught error',
|
|
89
|
+
error: error instanceof Error ? error.message : String(error),
|
|
90
|
+
});
|
|
89
91
|
return formatTextContents(getErrorMessage(error));
|
|
90
92
|
}
|
|
91
93
|
}
|
|
@@ -100,6 +102,6 @@ export class HsCreateFunctionTool extends Tool {
|
|
|
100
102
|
idempotentHint: false,
|
|
101
103
|
openWorldHint: false,
|
|
102
104
|
},
|
|
103
|
-
}, this.
|
|
105
|
+
}, input => this.wrappedHandler(input));
|
|
104
106
|
}
|
|
105
107
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { TextContentResponse
|
|
1
|
+
import { TextContentResponse } from '../../types.js';
|
|
2
|
+
import { Tool } from '../../Tool.js';
|
|
2
3
|
import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { McpLogger } from '../../utils/logger.js';
|
|
3
5
|
import { z } from 'zod';
|
|
4
6
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
5
7
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
@@ -13,7 +15,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
13
15
|
}, z.core.$strip>;
|
|
14
16
|
export type HsCreateModuleInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
15
17
|
export declare class HsCreateModuleTool extends Tool<HsCreateModuleInputSchema> {
|
|
16
|
-
constructor(mcpServer: McpServer);
|
|
18
|
+
constructor(mcpServer: McpServer, logger: McpLogger);
|
|
17
19
|
handler({ userSuppliedName, dest, moduleLabel, reactType, contentTypes, global, availableForNewContent, absoluteCurrentWorkingDirectory, }: HsCreateModuleInputSchema): Promise<TextContentResponse>;
|
|
18
20
|
register(): RegisteredTool;
|
|
19
21
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Tool } from '../../
|
|
1
|
+
import { Tool } from '../../Tool.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
4
|
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
|
-
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
6
|
import { addFlag } from '../../utils/command.js';
|
|
8
7
|
import { CONTENT_TYPES } from '../../../types/Cms.js';
|
|
9
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
@@ -51,12 +50,11 @@ const inputSchema = {
|
|
|
51
50
|
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
52
51
|
const toolName = 'create-cms-module';
|
|
53
52
|
export class HsCreateModuleTool extends Tool {
|
|
54
|
-
constructor(mcpServer) {
|
|
55
|
-
super(mcpServer);
|
|
53
|
+
constructor(mcpServer, logger) {
|
|
54
|
+
super(mcpServer, logger, toolName);
|
|
56
55
|
}
|
|
57
56
|
async handler({ userSuppliedName, dest, moduleLabel, reactType, contentTypes, global, availableForNewContent, absoluteCurrentWorkingDirectory, }) {
|
|
58
57
|
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
59
|
-
await trackToolUsage(toolName);
|
|
60
58
|
const content = [];
|
|
61
59
|
// Always require a name
|
|
62
60
|
if (!userSuppliedName) {
|
|
@@ -108,6 +106,10 @@ export class HsCreateModuleTool extends Tool {
|
|
|
108
106
|
return formatTextContents(stdout, stderr);
|
|
109
107
|
}
|
|
110
108
|
catch (error) {
|
|
109
|
+
this.logger.debug(toolName, {
|
|
110
|
+
message: 'Handler caught error',
|
|
111
|
+
error: error instanceof Error ? error.message : String(error),
|
|
112
|
+
});
|
|
111
113
|
return formatTextContents(getErrorMessage(error));
|
|
112
114
|
}
|
|
113
115
|
}
|
|
@@ -122,6 +124,6 @@ export class HsCreateModuleTool extends Tool {
|
|
|
122
124
|
idempotentHint: false,
|
|
123
125
|
openWorldHint: false,
|
|
124
126
|
},
|
|
125
|
-
}, this.
|
|
127
|
+
}, input => this.wrappedHandler(input));
|
|
126
128
|
}
|
|
127
129
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { TextContentResponse
|
|
1
|
+
import { TextContentResponse } from '../../types.js';
|
|
2
|
+
import { Tool } from '../../Tool.js';
|
|
2
3
|
import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { McpLogger } from '../../utils/logger.js';
|
|
3
5
|
import { z } from 'zod';
|
|
4
6
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
5
7
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
@@ -18,7 +20,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
18
20
|
}, z.core.$strip>;
|
|
19
21
|
export type HsCreateTemplateInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
20
22
|
export declare class HsCreateTemplateTool extends Tool<HsCreateTemplateInputSchema> {
|
|
21
|
-
constructor(mcpServer: McpServer);
|
|
23
|
+
constructor(mcpServer: McpServer, logger: McpLogger);
|
|
22
24
|
handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }: HsCreateTemplateInputSchema): Promise<TextContentResponse>;
|
|
23
25
|
register(): RegisteredTool;
|
|
24
26
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Tool } from '../../
|
|
1
|
+
import { Tool } from '../../Tool.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
4
|
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
|
-
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
6
|
import { addFlag } from '../../utils/command.js';
|
|
8
7
|
import { TEMPLATE_TYPES } from '../../../types/Cms.js';
|
|
9
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
@@ -27,12 +26,11 @@ const inputSchema = {
|
|
|
27
26
|
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
28
27
|
const toolName = 'create-cms-template';
|
|
29
28
|
export class HsCreateTemplateTool extends Tool {
|
|
30
|
-
constructor(mcpServer) {
|
|
31
|
-
super(mcpServer);
|
|
29
|
+
constructor(mcpServer, logger) {
|
|
30
|
+
super(mcpServer, logger, toolName);
|
|
32
31
|
}
|
|
33
32
|
async handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }) {
|
|
34
33
|
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
35
|
-
await trackToolUsage(toolName);
|
|
36
34
|
const content = [];
|
|
37
35
|
// Always require a name
|
|
38
36
|
if (!userSuppliedName) {
|
|
@@ -65,6 +63,10 @@ export class HsCreateTemplateTool extends Tool {
|
|
|
65
63
|
return formatTextContents(stdout, stderr);
|
|
66
64
|
}
|
|
67
65
|
catch (error) {
|
|
66
|
+
this.logger.debug(toolName, {
|
|
67
|
+
message: 'Handler caught error',
|
|
68
|
+
error: error instanceof Error ? error.message : String(error),
|
|
69
|
+
});
|
|
68
70
|
return formatTextContents(getErrorMessage(error));
|
|
69
71
|
}
|
|
70
72
|
}
|
|
@@ -79,6 +81,6 @@ export class HsCreateTemplateTool extends Tool {
|
|
|
79
81
|
idempotentHint: false,
|
|
80
82
|
openWorldHint: false,
|
|
81
83
|
},
|
|
82
|
-
}, this.
|
|
84
|
+
}, input => this.wrappedHandler(input));
|
|
83
85
|
}
|
|
84
86
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { TextContentResponse
|
|
1
|
+
import { TextContentResponse } from '../../types.js';
|
|
2
|
+
import { Tool } from '../../Tool.js';
|
|
2
3
|
import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { McpLogger } from '../../utils/logger.js';
|
|
3
5
|
import { z } from 'zod';
|
|
4
6
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
5
7
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
@@ -11,7 +13,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
11
13
|
}, z.core.$strip>;
|
|
12
14
|
export type HsFunctionLogsInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
13
15
|
export declare class HsFunctionLogsTool extends Tool<HsFunctionLogsInputSchema> {
|
|
14
|
-
constructor(mcpServer: McpServer);
|
|
16
|
+
constructor(mcpServer: McpServer, logger: McpLogger);
|
|
15
17
|
handler({ endpoint, account, latest, compact, limit, absoluteCurrentWorkingDirectory, }: HsFunctionLogsInputSchema): Promise<TextContentResponse>;
|
|
16
18
|
register(): RegisteredTool;
|
|
17
19
|
}
|