toolcraft 0.0.23 → 0.0.24
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/README.md +2 -2
- package/dist/cli.compile-check.js +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +50 -13
- package/dist/error-report.js +32 -3
- package/dist/human-in-loop/approval-tasks.d.ts +1 -0
- package/dist/human-in-loop/approval-tasks.js +7 -5
- package/dist/human-in-loop/approvals-commands.js +51 -8
- package/dist/human-in-loop/runner.js +24 -19
- package/dist/human-in-loop/state-machine.d.ts +3 -3
- package/dist/human-in-loop/state-machine.js +13 -5
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -1
- package/dist/mcp-proxy.js +85 -19
- package/dist/mcp.compile-check.js +1 -0
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +50 -8
- package/dist/renderer.js +119 -13
- package/dist/sdk.compile-check.js +1 -0
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.js +56 -11
- package/node_modules/@poe-code/agent-defs/dist/registry.d.ts +1 -1
- package/node_modules/@poe-code/agent-defs/dist/registry.js +22 -11
- package/node_modules/@poe-code/agent-defs/package.json +1 -1
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/osascript-script.js +5 -1
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/osascript.js +1 -1
- package/node_modules/@poe-code/agent-human-in-loop/package.json +1 -1
- package/node_modules/@poe-code/agent-mcp-config/dist/apply.d.ts +1 -1
- package/node_modules/@poe-code/agent-mcp-config/dist/apply.js +41 -92
- package/node_modules/@poe-code/agent-mcp-config/dist/configs.js +4 -1
- package/node_modules/@poe-code/agent-mcp-config/dist/shapes.d.ts +14 -2
- package/node_modules/@poe-code/agent-mcp-config/dist/shapes.js +11 -4
- package/node_modules/@poe-code/agent-mcp-config/package.json +1 -1
- package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.js +200 -22
- package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.js +7 -1
- package/node_modules/@poe-code/config-mutations/dist/formats/index.js +1 -1
- package/node_modules/@poe-code/config-mutations/dist/formats/json.js +11 -7
- package/node_modules/@poe-code/config-mutations/dist/formats/object.d.ts +4 -0
- package/node_modules/@poe-code/config-mutations/dist/formats/object.js +27 -0
- package/node_modules/@poe-code/config-mutations/dist/formats/toml.js +12 -9
- package/node_modules/@poe-code/config-mutations/dist/formats/yaml.js +12 -9
- package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.d.ts +11 -1
- package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.js +10 -1
- package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.js +25 -1
- package/node_modules/@poe-code/config-mutations/dist/types.d.ts +12 -2
- package/node_modules/@poe-code/config-mutations/package.json +1 -1
- package/node_modules/@poe-code/design-system/dist/acp/components.js +3 -1
- package/node_modules/@poe-code/design-system/dist/components/browser.d.ts +1 -1
- package/node_modules/@poe-code/design-system/dist/components/browser.js +6 -1
- package/node_modules/@poe-code/design-system/dist/components/color.js +9 -8
- package/node_modules/@poe-code/design-system/dist/components/command-errors.js +3 -2
- package/node_modules/@poe-code/design-system/dist/components/detail-card.d.ts +22 -0
- package/node_modules/@poe-code/design-system/dist/components/detail-card.js +69 -0
- package/node_modules/@poe-code/design-system/dist/components/help-formatter.js +88 -11
- package/node_modules/@poe-code/design-system/dist/components/index.d.ts +1 -1
- package/node_modules/@poe-code/design-system/dist/components/index.js +1 -1
- package/node_modules/@poe-code/design-system/dist/components/table.d.ts +2 -0
- package/node_modules/@poe-code/design-system/dist/components/table.js +82 -5
- package/node_modules/@poe-code/design-system/dist/components/template.d.ts +4 -0
- package/node_modules/@poe-code/design-system/dist/components/template.js +198 -32
- package/node_modules/@poe-code/design-system/dist/components/text.js +29 -5
- package/node_modules/@poe-code/design-system/dist/dashboard/ansi.d.ts +2 -2
- package/node_modules/@poe-code/design-system/dist/dashboard/ansi.js +77 -32
- package/node_modules/@poe-code/design-system/dist/dashboard/buffer.js +28 -5
- package/node_modules/@poe-code/design-system/dist/dashboard/components/output-pane.js +45 -28
- package/node_modules/@poe-code/design-system/dist/dashboard/terminal-width.d.ts +4 -0
- package/node_modules/@poe-code/design-system/dist/dashboard/terminal-width.js +71 -0
- package/node_modules/@poe-code/design-system/dist/dashboard/types.d.ts +1 -0
- package/node_modules/@poe-code/design-system/dist/explorer/events.d.ts +6 -0
- package/node_modules/@poe-code/design-system/dist/explorer/reducer.js +32 -10
- package/node_modules/@poe-code/design-system/dist/explorer/render/detail.js +3 -0
- package/node_modules/@poe-code/design-system/dist/explorer/runtime.js +57 -6
- package/node_modules/@poe-code/design-system/dist/explorer/state.d.ts +1 -0
- package/node_modules/@poe-code/design-system/dist/explorer/state.js +12 -15
- package/node_modules/@poe-code/design-system/dist/index.d.ts +3 -1
- package/node_modules/@poe-code/design-system/dist/index.js +2 -1
- package/node_modules/@poe-code/design-system/dist/prompts/primitives/intro.js +2 -1
- package/node_modules/@poe-code/design-system/dist/prompts/primitives/log.js +8 -5
- package/node_modules/@poe-code/design-system/dist/prompts/primitives/note.js +1 -1
- package/node_modules/@poe-code/design-system/dist/static/menu.js +8 -2
- package/node_modules/@poe-code/design-system/dist/static/spinner.js +10 -4
- package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser/frontmatter.js +9 -2
- package/node_modules/@poe-code/design-system/dist/terminal-markdown/renderer.js +19 -2
- package/node_modules/@poe-code/design-system/package.json +2 -1
- package/node_modules/@poe-code/process-runner/dist/docker/docker-execution-env.js +244 -110
- package/node_modules/@poe-code/process-runner/dist/docker/docker-runner.js +16 -4
- package/node_modules/@poe-code/process-runner/dist/host/host-execution-env.js +3 -2
- package/node_modules/@poe-code/process-runner/dist/host/host-runner.js +16 -1
- package/node_modules/@poe-code/process-runner/dist/index.d.ts +1 -0
- package/node_modules/@poe-code/process-runner/dist/index.js +1 -0
- package/node_modules/@poe-code/process-runner/dist/testing/mock-runner.js +30 -8
- package/node_modules/@poe-code/process-runner/dist/types.d.ts +3 -0
- package/node_modules/@poe-code/process-runner/dist/workspace-transfer.d.ts +57 -0
- package/node_modules/@poe-code/process-runner/dist/workspace-transfer.js +484 -0
- package/node_modules/@poe-code/process-runner/package.json +1 -1
- package/node_modules/@poe-code/task-list/README.md +0 -2
- package/node_modules/@poe-code/task-list/dist/backends/gh-issues-client.js +3 -0
- package/node_modules/@poe-code/task-list/dist/backends/gh-issues-sync.js +89 -59
- package/node_modules/@poe-code/task-list/dist/backends/gh-issues.d.ts +9 -3
- package/node_modules/@poe-code/task-list/dist/backends/gh-issues.js +460 -99
- package/node_modules/@poe-code/task-list/dist/backends/markdown-dir.js +156 -154
- package/node_modules/@poe-code/task-list/dist/backends/utils.d.ts +2 -0
- package/node_modules/@poe-code/task-list/dist/backends/utils.js +79 -0
- package/node_modules/@poe-code/task-list/dist/backends/yaml-file.js +120 -132
- package/node_modules/@poe-code/task-list/dist/index.d.ts +3 -1
- package/node_modules/@poe-code/task-list/dist/index.js +2 -0
- package/node_modules/@poe-code/task-list/dist/move.d.ts +2 -0
- package/node_modules/@poe-code/task-list/dist/move.js +215 -0
- package/node_modules/@poe-code/task-list/dist/open.js +3 -4
- package/node_modules/@poe-code/task-list/dist/state-machine.js +3 -1
- package/node_modules/@poe-code/task-list/dist/state.js +9 -0
- package/node_modules/@poe-code/task-list/dist/types.d.ts +48 -13
- package/node_modules/@poe-code/task-list/package.json +1 -2
- package/node_modules/auth-store/dist/create-secret-store.js +4 -1
- package/node_modules/auth-store/dist/encrypted-file-store.d.ts +7 -0
- package/node_modules/auth-store/dist/encrypted-file-store.js +69 -7
- package/node_modules/auth-store/dist/index.d.ts +1 -1
- package/node_modules/auth-store/dist/keychain-store.d.ts +4 -1
- package/node_modules/auth-store/dist/keychain-store.js +18 -16
- package/node_modules/auth-store/dist/provider-store.d.ts +5 -1
- package/node_modules/auth-store/dist/provider-store.js +55 -7
- package/node_modules/auth-store/dist/types.d.ts +3 -1
- package/node_modules/auth-store/package.json +2 -1
- package/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +46 -15
- package/node_modules/mcp-oauth/dist/client/loopback-authorization.js +49 -12
- package/node_modules/mcp-oauth/dist/client/token-endpoint.js +6 -1
- package/node_modules/mcp-oauth/dist/server/jwks-token-verifier.js +1 -1
- package/node_modules/mcp-oauth/package.json +1 -0
- package/node_modules/tiny-mcp-client/.turbo/turbo-build.log +1 -1
- package/node_modules/tiny-mcp-client/dist/internal.d.ts +8 -4
- package/node_modules/tiny-mcp-client/dist/internal.js +237 -67
- package/node_modules/tiny-mcp-client/dist/oauth-discovery.d.ts +1 -1
- package/node_modules/tiny-mcp-client/dist/oauth-discovery.js +4 -7
- package/node_modules/tiny-mcp-client/package.json +2 -1
- package/node_modules/tiny-mcp-client/src/http-oauth.integration.test.ts +1 -1
- package/node_modules/tiny-mcp-client/src/http-oauth.test.ts +46 -0
- package/node_modules/tiny-mcp-client/src/internal.ts +279 -77
- package/node_modules/tiny-mcp-client/src/mcp-client-tiny-stdio-test-server-tools.test.ts +1 -1
- package/node_modules/tiny-mcp-client/src/oauth-discovery.ts +5 -10
- package/node_modules/tiny-mcp-client/src/transports.test.ts +588 -6
- package/package.json +10 -12
- package/node_modules/@poe-code/file-lock/README.md +0 -52
- package/node_modules/@poe-code/file-lock/dist/index.d.ts +0 -1
- package/node_modules/@poe-code/file-lock/dist/index.js +0 -1
- package/node_modules/@poe-code/file-lock/dist/lock.d.ts +0 -27
- package/node_modules/@poe-code/file-lock/dist/lock.js +0 -203
- package/node_modules/@poe-code/file-lock/package.json +0 -23
package/dist/mcp-proxy.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { mkdir, readFile, rename,
|
|
2
|
+
import { lstat, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
4
5
|
import { createLogger } from "@poe-code/design-system";
|
|
5
6
|
import { HttpTransport, McpClient, StdioTransport } from "tiny-mcp-client";
|
|
6
7
|
import { convertJsonSchema } from "./json-schema-converter.js";
|
|
@@ -153,6 +154,7 @@ async function ensureConnected(connection) {
|
|
|
153
154
|
}
|
|
154
155
|
async function readCache(cachePath) {
|
|
155
156
|
try {
|
|
157
|
+
await assertCachePathHasNoSymlinks(cachePath);
|
|
156
158
|
const raw = await readFile(cachePath, "utf8");
|
|
157
159
|
const parsed = JSON.parse(raw);
|
|
158
160
|
if (parsed === null ||
|
|
@@ -168,6 +170,7 @@ async function readCache(cachePath) {
|
|
|
168
170
|
fetchedAt: typeof parsed.fetchedAt === "string" ? parsed.fetchedAt : new Date(0).toISOString(),
|
|
169
171
|
tools: parsed.tools,
|
|
170
172
|
upstream: parsed.upstream,
|
|
173
|
+
configFingerprint: typeof parsed.configFingerprint === "string" ? parsed.configFingerprint : undefined,
|
|
171
174
|
version: parsed.version === 1 ? 1 : 1,
|
|
172
175
|
};
|
|
173
176
|
}
|
|
@@ -181,12 +184,17 @@ async function readCache(cachePath) {
|
|
|
181
184
|
}
|
|
182
185
|
async function writeCache(cachePath, cache) {
|
|
183
186
|
const directory = path.dirname(cachePath);
|
|
184
|
-
const tempPath = `${cachePath}.tmp`;
|
|
187
|
+
const tempPath = `${cachePath}.tmp-${randomUUID()}`;
|
|
188
|
+
await assertCachePathHasNoSymlinks(cachePath);
|
|
189
|
+
await assertCachePathHasNoSymlinks(tempPath);
|
|
185
190
|
await mkdir(directory, { recursive: true });
|
|
191
|
+
await assertCachePathHasNoSymlinks(directory);
|
|
186
192
|
await writeFile(tempPath, `${JSON.stringify(cache, null, 2)}\n`);
|
|
193
|
+
await assertCachePathHasNoSymlinks(tempPath);
|
|
194
|
+
await assertCachePathHasNoSymlinks(cachePath);
|
|
187
195
|
await rename(tempPath, cachePath);
|
|
188
196
|
}
|
|
189
|
-
async function fetchCache(name, config
|
|
197
|
+
async function fetchCache(name, config) {
|
|
190
198
|
const logger = createLogger((message) => {
|
|
191
199
|
process.stderr.write(`${message}\n`);
|
|
192
200
|
});
|
|
@@ -210,27 +218,16 @@ async function fetchCache(name, config, cachePath) {
|
|
|
210
218
|
$schema: MCP_PROXY_SCHEMA_URL,
|
|
211
219
|
version: 1,
|
|
212
220
|
upstream,
|
|
221
|
+
configFingerprint: fingerprintMcpServerConfig(config),
|
|
213
222
|
fetchedAt: new Date().toISOString(),
|
|
214
223
|
tools,
|
|
215
224
|
};
|
|
216
|
-
await writeCache(cachePath, cache);
|
|
217
|
-
logger.info(`MCP ${name}: wrote ${cachePath}`);
|
|
218
225
|
return cache;
|
|
219
226
|
}
|
|
220
227
|
finally {
|
|
221
228
|
await client.close();
|
|
222
229
|
}
|
|
223
230
|
}
|
|
224
|
-
async function deleteCacheIfPresent(cachePath) {
|
|
225
|
-
try {
|
|
226
|
-
await unlink(cachePath);
|
|
227
|
-
}
|
|
228
|
-
catch (error) {
|
|
229
|
-
if (error.code !== "ENOENT") {
|
|
230
|
-
throw error;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
231
|
function populateGroupFromTools(group, tools, rename, connection) {
|
|
235
232
|
removeProxyChildren(group);
|
|
236
233
|
for (const tool of tools) {
|
|
@@ -262,6 +259,31 @@ function populateGroupFromTools(group, tools, rename, connection) {
|
|
|
262
259
|
parent.children.push(createProxyCommand(parent, tool, commandName, connection));
|
|
263
260
|
}
|
|
264
261
|
}
|
|
262
|
+
function replaceProxyChildrenSafely(group, tools, rename, connection) {
|
|
263
|
+
const previousChildren = snapshotGroupChildren(group);
|
|
264
|
+
try {
|
|
265
|
+
populateGroupFromTools(group, tools, rename, connection);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
for (const [capturedGroup, children] of previousChildren) {
|
|
269
|
+
capturedGroup.children = children;
|
|
270
|
+
}
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function snapshotGroupChildren(group) {
|
|
275
|
+
const snapshot = new Map();
|
|
276
|
+
const visit = (current) => {
|
|
277
|
+
snapshot.set(current, [...current.children]);
|
|
278
|
+
for (const child of current.children) {
|
|
279
|
+
if (child.kind === "group") {
|
|
280
|
+
visit(child);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
visit(group);
|
|
285
|
+
return snapshot;
|
|
286
|
+
}
|
|
265
287
|
function isRefreshRequested(name, refresh) {
|
|
266
288
|
if (refresh === "all") {
|
|
267
289
|
return true;
|
|
@@ -279,19 +301,31 @@ async function resolveSingleProxy(group, options) {
|
|
|
279
301
|
const cachePath = resolveCachePath(name, options.projectRoot);
|
|
280
302
|
const refresh = parseRefreshEnv(process.env.TOOLCRAFT_MCP_REFRESH);
|
|
281
303
|
let cache;
|
|
304
|
+
let shouldWriteCache = false;
|
|
282
305
|
if (isRefreshRequested(name, refresh)) {
|
|
283
|
-
await
|
|
284
|
-
|
|
306
|
+
cache = await fetchCache(name, config);
|
|
307
|
+
shouldWriteCache = true;
|
|
285
308
|
}
|
|
286
309
|
else {
|
|
287
|
-
|
|
310
|
+
const storedCache = await readCache(cachePath);
|
|
311
|
+
if (storedCache && cacheMatchesConfig(storedCache, config)) {
|
|
312
|
+
cache = storedCache;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
cache = await fetchCache(name, config);
|
|
316
|
+
shouldWriteCache = true;
|
|
317
|
+
}
|
|
288
318
|
}
|
|
289
319
|
const tools = filterAllowlistedTools(cache.tools, internal.tools);
|
|
290
320
|
validateRenameMap(name, tools, internal.rename);
|
|
291
321
|
const previousConnection = getProxyConnection(group);
|
|
292
322
|
const nextConnection = createConnection(name, config);
|
|
293
323
|
try {
|
|
294
|
-
|
|
324
|
+
replaceProxyChildrenSafely(group, tools, internal.rename, nextConnection);
|
|
325
|
+
if (shouldWriteCache) {
|
|
326
|
+
await writeCache(cachePath, cache);
|
|
327
|
+
createLogger((message) => process.stderr.write(`${message}\n`)).info(`MCP ${name}: wrote ${cachePath}`);
|
|
328
|
+
}
|
|
295
329
|
setProxyConnection(group, nextConnection);
|
|
296
330
|
}
|
|
297
331
|
catch (error) {
|
|
@@ -309,6 +343,12 @@ async function resolveSingleProxy(group, options) {
|
|
|
309
343
|
throw new Error(`couldn't discover MCP ${name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
310
344
|
}
|
|
311
345
|
}
|
|
346
|
+
function cacheMatchesConfig(cache, config) {
|
|
347
|
+
return cache.configFingerprint === fingerprintMcpServerConfig(config);
|
|
348
|
+
}
|
|
349
|
+
function fingerprintMcpServerConfig(config) {
|
|
350
|
+
return createHash("sha256").update(JSON.stringify(config)).digest("hex");
|
|
351
|
+
}
|
|
312
352
|
function collectProxyGroups(root) {
|
|
313
353
|
const groups = [];
|
|
314
354
|
function visit(group) {
|
|
@@ -348,8 +388,34 @@ export function resolveCachePath(name, projectRoot) {
|
|
|
348
388
|
if (resolvedProjectRoot === undefined) {
|
|
349
389
|
throw new Error(`Could not find package.json above "${process.cwd()}" while resolving MCP cache path.`);
|
|
350
390
|
}
|
|
391
|
+
if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
|
|
392
|
+
throw new Error(`MCP proxy group name must be a file-safe name: "${name}".`);
|
|
393
|
+
}
|
|
351
394
|
return path.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
|
|
352
395
|
}
|
|
396
|
+
async function assertCachePathHasNoSymlinks(filePath) {
|
|
397
|
+
let currentPath = filePath;
|
|
398
|
+
while (true) {
|
|
399
|
+
try {
|
|
400
|
+
if ((await lstat(currentPath)).isSymbolicLink()) {
|
|
401
|
+
throw new Error(`MCP cache path must not contain symbolic links: ${currentPath}.`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
if (error.code !== "ENOENT") {
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (path.basename(currentPath) === ".toolcraft") {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const parentPath = path.dirname(currentPath);
|
|
413
|
+
if (parentPath === currentPath) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
currentPath = parentPath;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
353
419
|
export function parseRefreshEnv(value) {
|
|
354
420
|
const trimmed = value?.trim();
|
|
355
421
|
if (trimmed === undefined || trimmed.length === 0) {
|
package/dist/mcp.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type CmdkitServer = Omit<TinyServer, "connect"> & {
|
|
|
7
7
|
connect(transport: SDKTransport): Promise<void>;
|
|
8
8
|
};
|
|
9
9
|
export interface RunMCPOptions<TServices extends object = Record<string, unknown>> {
|
|
10
|
+
approvals?: boolean;
|
|
10
11
|
name: string;
|
|
11
12
|
version?: string;
|
|
12
13
|
humanInLoop?: HumanInLoopRuntimeOptions;
|
package/dist/mcp.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { access, lstat, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { createServer, JSON_RPC_ERROR_CODES, ToolError } from "tiny-stdio-mcp-server";
|
|
3
3
|
import { toJsonSchema } from "toolcraft-schema";
|
|
4
4
|
import { ToolcraftBugError, UserError, assertCommandRequirements, resolveCommandSecrets } from "./index.js";
|
|
@@ -104,7 +104,10 @@ function createFs() {
|
|
|
104
104
|
catch {
|
|
105
105
|
return false;
|
|
106
106
|
}
|
|
107
|
-
}
|
|
107
|
+
},
|
|
108
|
+
lstat: async (path) => lstat(path),
|
|
109
|
+
rename: async (fromPath, toPath) => rename(fromPath, toPath),
|
|
110
|
+
unlink: async (path) => unlink(path)
|
|
108
111
|
};
|
|
109
112
|
}
|
|
110
113
|
function createEnv(values = process.env) {
|
|
@@ -181,8 +184,24 @@ function matchesAllowlist(toolName, allowlist) {
|
|
|
181
184
|
function formatToolName(path) {
|
|
182
185
|
return path.map((segment) => formatSegment(segment, "snake")).join("__");
|
|
183
186
|
}
|
|
187
|
+
function validateUniqueMCPParameterFields(schema, casing) {
|
|
188
|
+
const sourceKeysByField = new Map();
|
|
189
|
+
for (const [key, rawChildSchema] of Object.entries(schema.shape)) {
|
|
190
|
+
const field = formatSegment(key, casing);
|
|
191
|
+
const existingKey = sourceKeysByField.get(field);
|
|
192
|
+
if (existingKey !== undefined) {
|
|
193
|
+
throw new UserError(`Parameters "${existingKey}" and "${key}" use conflicting MCP field "${field}".`);
|
|
194
|
+
}
|
|
195
|
+
sourceKeysByField.set(field, key);
|
|
196
|
+
const childSchema = unwrapOptional(rawChildSchema);
|
|
197
|
+
if (childSchema.kind === "object") {
|
|
198
|
+
validateUniqueMCPParameterFields(childSchema, casing);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
184
202
|
function enumerateTools(root, casing, allowlist, omitRootToolNamePrefix) {
|
|
185
203
|
const tools = [];
|
|
204
|
+
const commandPathsByToolName = new Map();
|
|
186
205
|
function visit(node, toolPath, commandPath) {
|
|
187
206
|
if (node.kind === "command") {
|
|
188
207
|
if (!node.scope.includes("mcp")) {
|
|
@@ -196,9 +215,16 @@ function enumerateTools(root, casing, allowlist, omitRootToolNamePrefix) {
|
|
|
196
215
|
if (params === undefined || params.kind !== "object") {
|
|
197
216
|
throw new ToolcraftBugError(`command "${name}" must define an object params schema for MCP.`);
|
|
198
217
|
}
|
|
218
|
+
validateUniqueMCPParameterFields(params, casing);
|
|
219
|
+
const resolvedCommandPath = [...commandPath, node.name].join(".");
|
|
220
|
+
const existingPath = commandPathsByToolName.get(name);
|
|
221
|
+
if (existingPath !== undefined) {
|
|
222
|
+
throw new UserError(`MCP commands "${existingPath}" and "${resolvedCommandPath}" use conflicting tool name "${name}".`);
|
|
223
|
+
}
|
|
224
|
+
commandPathsByToolName.set(name, resolvedCommandPath);
|
|
199
225
|
tools.push({
|
|
200
226
|
command: node,
|
|
201
|
-
commandPath:
|
|
227
|
+
commandPath: resolvedCommandPath,
|
|
202
228
|
name,
|
|
203
229
|
description: buildToolDescription(node.description, params, casing),
|
|
204
230
|
inputSchema: applySchemaCasing(toJsonSchema(params), casing)
|
|
@@ -360,7 +386,12 @@ function validateObjectSchema(schema, value, casing, label, errors) {
|
|
|
360
386
|
const fieldLabel = label.length === 0 ? inputKey : `${label}.${inputKey}`;
|
|
361
387
|
if (!hasValue) {
|
|
362
388
|
if (childSchema.default !== undefined) {
|
|
363
|
-
result
|
|
389
|
+
Object.defineProperty(result, outputKey, {
|
|
390
|
+
value: childSchema.default,
|
|
391
|
+
enumerable: true,
|
|
392
|
+
configurable: true,
|
|
393
|
+
writable: true
|
|
394
|
+
});
|
|
364
395
|
continue;
|
|
365
396
|
}
|
|
366
397
|
if (isOptional(rawChildSchema)) {
|
|
@@ -369,7 +400,12 @@ function validateObjectSchema(schema, value, casing, label, errors) {
|
|
|
369
400
|
errors.push({ path: fieldLabel, message: `Missing required parameter "${fieldLabel}".` });
|
|
370
401
|
continue;
|
|
371
402
|
}
|
|
372
|
-
result
|
|
403
|
+
Object.defineProperty(result, outputKey, {
|
|
404
|
+
value: validateSchemaValue(rawChildSchema, value[inputKey], casing, fieldLabel, errors),
|
|
405
|
+
enumerable: true,
|
|
406
|
+
configurable: true,
|
|
407
|
+
writable: true
|
|
408
|
+
});
|
|
373
409
|
}
|
|
374
410
|
return result;
|
|
375
411
|
}
|
|
@@ -430,7 +466,11 @@ function createResolvedMCPServer(root, options) {
|
|
|
430
466
|
validateServices(services);
|
|
431
467
|
const tools = enumerateTools(root, casing, options.tools, options.omitRootToolNamePrefix ?? false);
|
|
432
468
|
const version = resolveMCPVersion(options.version);
|
|
433
|
-
const server = createServer({
|
|
469
|
+
const server = createServer({
|
|
470
|
+
name: options.name,
|
|
471
|
+
version,
|
|
472
|
+
validateToolArguments: false
|
|
473
|
+
});
|
|
434
474
|
for (const tool of tools) {
|
|
435
475
|
server.tool(tool.name, tool.description, tool.inputSchema, async (argumentsValue) => {
|
|
436
476
|
let params;
|
|
@@ -516,7 +556,8 @@ function createDeferredMCPServer(root, options) {
|
|
|
516
556
|
});
|
|
517
557
|
}
|
|
518
558
|
export function createMCPServer(roots, options) {
|
|
519
|
-
const
|
|
559
|
+
const normalizedRoot = normalizeRoots(roots);
|
|
560
|
+
const root = options.approvals === false ? normalizedRoot : mergeApprovalsGroup(normalizedRoot);
|
|
520
561
|
if (!hasMcpProxyGroups(root)) {
|
|
521
562
|
return createResolvedMCPServer(root, options);
|
|
522
563
|
}
|
|
@@ -524,7 +565,8 @@ export function createMCPServer(roots, options) {
|
|
|
524
565
|
}
|
|
525
566
|
export async function runMCP(roots, options) {
|
|
526
567
|
enableSourceMaps();
|
|
527
|
-
const
|
|
568
|
+
const normalizedRoot = normalizeRoots(roots);
|
|
569
|
+
const root = options.approvals === false ? normalizedRoot : mergeApprovalsGroup(normalizedRoot);
|
|
528
570
|
await resolveMcpProxies(root, { projectRoot: options.projectRoot });
|
|
529
571
|
const server = createResolvedMCPServer(root, options);
|
|
530
572
|
await server.listen();
|
package/dist/renderer.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import YAML from "yaml";
|
|
2
|
+
import { renderDetailCard } from "@poe-code/design-system";
|
|
2
3
|
function isObject(value) {
|
|
3
4
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4
5
|
}
|
|
@@ -62,19 +63,117 @@ function stringifyJson(value, spaces) {
|
|
|
62
63
|
return String(value);
|
|
63
64
|
}
|
|
64
65
|
}
|
|
66
|
+
function humanizeKey(key) {
|
|
67
|
+
let output = "";
|
|
68
|
+
let capitalizeNext = true;
|
|
69
|
+
for (const char of key) {
|
|
70
|
+
if (char === "_" || char === "-") {
|
|
71
|
+
output += " ";
|
|
72
|
+
capitalizeNext = false;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (char >= "A" && char <= "Z" && output.length > 0 && !output.endsWith(" ")) {
|
|
76
|
+
output += " ";
|
|
77
|
+
}
|
|
78
|
+
if (capitalizeNext) {
|
|
79
|
+
output += char.toUpperCase();
|
|
80
|
+
capitalizeNext = false;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
output += char;
|
|
84
|
+
}
|
|
85
|
+
return output;
|
|
86
|
+
}
|
|
87
|
+
function detailRows(result, depth = 0) {
|
|
88
|
+
const rows = [];
|
|
89
|
+
for (const [key, value] of Object.entries(result)) {
|
|
90
|
+
const label = `${" ".repeat(depth)}${humanizeKey(key)}`;
|
|
91
|
+
if (isObject(value)) {
|
|
92
|
+
if (Object.keys(value).length === 0) {
|
|
93
|
+
rows.push({ label, value: "{}" });
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
rows.push({ label, value: "" });
|
|
97
|
+
rows.push(...detailRows(value, depth + 1));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
rows.push({ label, value: displayScalar(value) });
|
|
101
|
+
}
|
|
102
|
+
return rows;
|
|
103
|
+
}
|
|
104
|
+
function displayScalar(value) {
|
|
105
|
+
if (typeof value === "boolean") {
|
|
106
|
+
return value ? "Yes" : "No";
|
|
107
|
+
}
|
|
108
|
+
if (Array.isArray(value) && value.every((entry) => !isObject(entry) && !Array.isArray(entry))) {
|
|
109
|
+
return value.map((entry) => displayScalar(entry)).join(", ") || "—";
|
|
110
|
+
}
|
|
111
|
+
return stringifyValue(value) || "—";
|
|
112
|
+
}
|
|
113
|
+
function isUrl(value) {
|
|
114
|
+
return typeof value === "string" && (value.startsWith("https://") || value.startsWith("http://"));
|
|
115
|
+
}
|
|
116
|
+
function compactUrl(value) {
|
|
117
|
+
try {
|
|
118
|
+
const url = new URL(value);
|
|
119
|
+
const tail = url.pathname.split("/").filter(Boolean).at(-1);
|
|
120
|
+
return tail ? `${url.hostname}/…/${tail}` : url.hostname;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function displayRowValue(value) {
|
|
127
|
+
return isUrl(value) ? compactUrl(value) : displayScalar(value);
|
|
128
|
+
}
|
|
129
|
+
function directScalarRows(result) {
|
|
130
|
+
return Object.entries(result)
|
|
131
|
+
.filter(([, value]) => !isObject(value) && !Array.isArray(value))
|
|
132
|
+
.map(([key, value]) => ({ label: humanizeKey(key), value: displayRowValue(value) }));
|
|
133
|
+
}
|
|
134
|
+
function directObjectSections(result) {
|
|
135
|
+
return Object.entries(result)
|
|
136
|
+
.filter(([, value]) => isObject(value))
|
|
137
|
+
.map(([key, value]) => ({ title: humanizeKey(key), rows: detailRows(value) }))
|
|
138
|
+
.filter((section) => section.rows.length > 0);
|
|
139
|
+
}
|
|
140
|
+
function renderObjectCard(result, primitives, title) {
|
|
141
|
+
const scalarRows = directScalarRows(result);
|
|
142
|
+
const nestedSections = directObjectSections(result);
|
|
143
|
+
const listRows = Object.entries(result)
|
|
144
|
+
.filter(([, value]) => Array.isArray(value))
|
|
145
|
+
.map(([key, value]) => ({ label: humanizeKey(key), value: displayScalar(value) }));
|
|
146
|
+
return renderDetailCard({
|
|
147
|
+
theme: primitives.getTheme(),
|
|
148
|
+
title,
|
|
149
|
+
sections: [
|
|
150
|
+
{ rows: scalarRows },
|
|
151
|
+
...nestedSections,
|
|
152
|
+
{ title: "Lists", rows: listRows }
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function richResultTitle(command) {
|
|
157
|
+
const description = command.description?.trim();
|
|
158
|
+
if (description && !description.includes("\n") && description.length <= 64) {
|
|
159
|
+
return description;
|
|
160
|
+
}
|
|
161
|
+
return command.name ? humanizeKey(command.name) : "Result";
|
|
162
|
+
}
|
|
65
163
|
export function renderObjectTable(result, primitives) {
|
|
66
|
-
const rows =
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
164
|
+
const rows = detailRows(result);
|
|
165
|
+
if (rows.length === 0) {
|
|
166
|
+
return "{}";
|
|
167
|
+
}
|
|
70
168
|
return primitives.renderTable({
|
|
71
169
|
theme: primitives.getTheme(),
|
|
170
|
+
variant: "detail",
|
|
72
171
|
columns: [
|
|
73
172
|
{
|
|
74
|
-
name: "
|
|
75
|
-
title: "
|
|
173
|
+
name: "label",
|
|
174
|
+
title: "Label",
|
|
76
175
|
alignment: "left",
|
|
77
|
-
maxLen: Math.max("
|
|
176
|
+
maxLen: Math.max("Label".length, ...rows.map((row) => row.label.length)),
|
|
78
177
|
},
|
|
79
178
|
{
|
|
80
179
|
name: "value",
|
|
@@ -111,9 +210,12 @@ export function renderArrayTable(result, primitives) {
|
|
|
111
210
|
name,
|
|
112
211
|
title: name,
|
|
113
212
|
alignment: "left",
|
|
114
|
-
maxLen: Math.max(name.length, ...result.map((row) => (name
|
|
213
|
+
maxLen: Math.max(name.length, ...result.map((row) => Object.prototype.hasOwnProperty.call(row, name) ? stringifyValue(row[name]).length : 0)),
|
|
115
214
|
})),
|
|
116
|
-
rows: result.map((row) => Object.fromEntries(columnNames.map((name) => [
|
|
215
|
+
rows: result.map((row) => Object.fromEntries(columnNames.map((name) => [
|
|
216
|
+
name,
|
|
217
|
+
Object.prototype.hasOwnProperty.call(row, name) ? stringifyValue(row[name]) : ""
|
|
218
|
+
]))),
|
|
117
219
|
});
|
|
118
220
|
}
|
|
119
221
|
function renderArrayMarkdown(result) {
|
|
@@ -124,11 +226,13 @@ function renderArrayMarkdown(result) {
|
|
|
124
226
|
const header = `| ${columnNames.join(" | ")} |`;
|
|
125
227
|
const separator = `| ${columnNames.map(() => ":---").join(" | ")} |`;
|
|
126
228
|
const rows = result.map((row) => `| ${columnNames
|
|
127
|
-
.map((name) => (
|
|
229
|
+
.map((name) => Object.prototype.hasOwnProperty.call(row, name)
|
|
230
|
+
? stringifyValue(row[name]).replaceAll("|", "\\|")
|
|
231
|
+
: "")
|
|
128
232
|
.join(" | ")} |`);
|
|
129
233
|
return [header, separator, ...rows].join("\n");
|
|
130
234
|
}
|
|
131
|
-
function autoRender(result, output,
|
|
235
|
+
function autoRender(command, result, output, primitives) {
|
|
132
236
|
if (result === null || result === undefined) {
|
|
133
237
|
if (output === "json") {
|
|
134
238
|
return stringifyJson({ ok: true }, 2);
|
|
@@ -151,6 +255,7 @@ function autoRender(result, output, _primitives) {
|
|
|
151
255
|
if (output === "json") {
|
|
152
256
|
return stringifyJson(result, 2);
|
|
153
257
|
}
|
|
258
|
+
return renderObjectCard(result, primitives, richResultTitle(command));
|
|
154
259
|
}
|
|
155
260
|
if (isArrayOfObjects(result)) {
|
|
156
261
|
if (output === "md") {
|
|
@@ -159,6 +264,7 @@ function autoRender(result, output, _primitives) {
|
|
|
159
264
|
if (output === "json") {
|
|
160
265
|
return stringifyJson(result, 2);
|
|
161
266
|
}
|
|
267
|
+
return renderArrayTable(result, primitives);
|
|
162
268
|
}
|
|
163
269
|
if (output === "rich") {
|
|
164
270
|
return YAML.stringify(result);
|
|
@@ -175,7 +281,7 @@ export function renderResult(command, result, output, primitives, write = (chunk
|
|
|
175
281
|
const unwrapped = unwrapMcpEnvelope(result);
|
|
176
282
|
result = unwrapped.result;
|
|
177
283
|
if (unwrapped.mcpError) {
|
|
178
|
-
const payload = autoRender(result, output, primitives);
|
|
284
|
+
const payload = autoRender(command, result, output, primitives);
|
|
179
285
|
if (payload.length > 0) {
|
|
180
286
|
write(`${payload}\n`, "stderr");
|
|
181
287
|
}
|
|
@@ -199,7 +305,7 @@ export function renderResult(command, result, output, primitives, write = (chunk
|
|
|
199
305
|
command.render.rich(result, primitives);
|
|
200
306
|
return { mcpError: false };
|
|
201
307
|
}
|
|
202
|
-
const payload = autoRender(result, output, primitives);
|
|
308
|
+
const payload = autoRender(command, result, output, primitives);
|
|
203
309
|
if (payload.length > 0) {
|
|
204
310
|
write(`${payload}\n`);
|
|
205
311
|
}
|
package/dist/sdk.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ type SDKNodeShape<TNode, TInheritedScope extends ScopeInput, TInheritedHumanInLo
|
|
|
61
61
|
} : never : EmptyRecord;
|
|
62
62
|
type SDKChildrenShape<TChildren, TInheritedScope extends ScopeInput, TInheritedHumanInLoopMode extends HumanInLoopMode | undefined> = Simplify<UnionToIntersection<SDKNodeShape<RawChildrenValue<TChildren>, TInheritedScope, TInheritedHumanInLoopMode>>>;
|
|
63
63
|
export interface CreateSDKOptions<TServices extends object = Record<string, unknown>> {
|
|
64
|
+
approvals?: boolean;
|
|
64
65
|
services?: TServices;
|
|
65
66
|
casing?: "camel";
|
|
66
67
|
humanInLoop?: HumanInLoopRuntimeOptions;
|
package/dist/sdk.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { access, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { ToolcraftBugError, assertCommandRequirements, resolveCommandSecrets } from "./index.js";
|
|
1
|
+
import { access, lstat, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { ToolcraftBugError, UserError, assertCommandRequirements, resolveCommandSecrets } from "./index.js";
|
|
3
3
|
import { writeErrorReport } from "./error-report.js";
|
|
4
4
|
import { mergeApprovalsGroup } from "./human-in-loop/approvals-commands.js";
|
|
5
5
|
import { invokeWithHumanInLoop } from "./human-in-loop/index.js";
|
|
@@ -85,7 +85,10 @@ function createFs() {
|
|
|
85
85
|
catch {
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
|
-
}
|
|
88
|
+
},
|
|
89
|
+
lstat: async (path) => lstat(path),
|
|
90
|
+
rename: async (fromPath, toPath) => rename(fromPath, toPath),
|
|
91
|
+
unlink: async (path) => unlink(path)
|
|
89
92
|
};
|
|
90
93
|
}
|
|
91
94
|
function createEnv(values = process.env) {
|
|
@@ -206,7 +209,12 @@ function validateObjectSchema(schema, value, label, errors) {
|
|
|
206
209
|
const fieldLabel = label.length === 0 ? inputKey : `${label}.${inputKey}`;
|
|
207
210
|
if (!hasValue) {
|
|
208
211
|
if (childSchema.default !== undefined) {
|
|
209
|
-
result
|
|
212
|
+
Object.defineProperty(result, outputKey, {
|
|
213
|
+
value: childSchema.default,
|
|
214
|
+
enumerable: true,
|
|
215
|
+
configurable: true,
|
|
216
|
+
writable: true
|
|
217
|
+
});
|
|
210
218
|
continue;
|
|
211
219
|
}
|
|
212
220
|
if (isOptional(rawChildSchema)) {
|
|
@@ -215,10 +223,30 @@ function validateObjectSchema(schema, value, label, errors) {
|
|
|
215
223
|
errors.push({ path: fieldLabel, message: `Missing required parameter "${fieldLabel}".` });
|
|
216
224
|
continue;
|
|
217
225
|
}
|
|
218
|
-
result
|
|
226
|
+
Object.defineProperty(result, outputKey, {
|
|
227
|
+
value: validateSchemaValue(rawChildSchema, value[inputKey], fieldLabel, errors),
|
|
228
|
+
enumerable: true,
|
|
229
|
+
configurable: true,
|
|
230
|
+
writable: true
|
|
231
|
+
});
|
|
219
232
|
}
|
|
220
233
|
return result;
|
|
221
234
|
}
|
|
235
|
+
function validateUniqueSDKParameterMembers(schema) {
|
|
236
|
+
const sourceKeysByMember = new Map();
|
|
237
|
+
for (const [key, rawChildSchema] of Object.entries(schema.shape)) {
|
|
238
|
+
const member = formatSegment(key);
|
|
239
|
+
const existingKey = sourceKeysByMember.get(member);
|
|
240
|
+
if (existingKey !== undefined) {
|
|
241
|
+
throw new UserError(`Parameters "${existingKey}" and "${key}" use conflicting SDK member "${member}".`);
|
|
242
|
+
}
|
|
243
|
+
sourceKeysByMember.set(member, key);
|
|
244
|
+
const childSchema = unwrapOptional(rawChildSchema);
|
|
245
|
+
if (childSchema.kind === "object") {
|
|
246
|
+
validateUniqueSDKParameterMembers(childSchema);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
222
250
|
function validateSDKArguments(schema, argumentsValue) {
|
|
223
251
|
const errors = [];
|
|
224
252
|
const result = validateObjectSchema(schema, argumentsValue ?? {}, "", errors);
|
|
@@ -238,7 +266,7 @@ function defineMember(target, key, value) {
|
|
|
238
266
|
}
|
|
239
267
|
export function createSDK(root, options = {}) {
|
|
240
268
|
enableSourceMaps();
|
|
241
|
-
const mergedRoot = mergeApprovalsGroup(root);
|
|
269
|
+
const mergedRoot = options.approvals === false ? root : mergeApprovalsGroup(root);
|
|
242
270
|
if (!hasMcpProxyGroups(mergedRoot)) {
|
|
243
271
|
return createResolvedSDK(mergedRoot, options);
|
|
244
272
|
}
|
|
@@ -251,6 +279,10 @@ function createResolvedSDK(root, options = {}) {
|
|
|
251
279
|
validateServices(services);
|
|
252
280
|
function build(node, path) {
|
|
253
281
|
if (node.kind === "command") {
|
|
282
|
+
const sdkParamsSchema = filterSchemaForScope(node.params, "sdk");
|
|
283
|
+
if (sdkParamsSchema?.kind === "object") {
|
|
284
|
+
validateUniqueSDKParameterMembers(sdkParamsSchema);
|
|
285
|
+
}
|
|
254
286
|
return async (params) => {
|
|
255
287
|
const commandPath = [...path, node.name].join(".");
|
|
256
288
|
let secrets;
|
|
@@ -298,19 +330,32 @@ function createResolvedSDK(root, options = {}) {
|
|
|
298
330
|
};
|
|
299
331
|
}
|
|
300
332
|
const output = {};
|
|
333
|
+
const sourceNamesByMember = new Map();
|
|
301
334
|
const nextPath = node === root ? path : [...path, node.name];
|
|
302
335
|
for (const child of node.children) {
|
|
336
|
+
let childValue;
|
|
303
337
|
if (child.kind === "command") {
|
|
304
338
|
if (!child.scope.includes("sdk")) {
|
|
305
339
|
continue;
|
|
306
340
|
}
|
|
307
|
-
|
|
308
|
-
|
|
341
|
+
childValue = build(child, nextPath);
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
childValue = build(child, nextPath);
|
|
345
|
+
if (!isPlainObject(childValue) || Object.keys(childValue).length === 0) {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const member = formatSegment(child.name);
|
|
350
|
+
if (member === "then") {
|
|
351
|
+
throw new UserError(`SDK member "${child.name}" uses reserved member "then".`);
|
|
309
352
|
}
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
312
|
-
|
|
353
|
+
const existingName = sourceNamesByMember.get(member);
|
|
354
|
+
if (existingName !== undefined) {
|
|
355
|
+
throw new UserError(`SDK members "${existingName}" and "${child.name}" use conflicting member "${member}".`);
|
|
313
356
|
}
|
|
357
|
+
sourceNamesByMember.set(member, child.name);
|
|
358
|
+
defineMember(output, member, childValue);
|
|
314
359
|
}
|
|
315
360
|
return output;
|
|
316
361
|
}
|