@oh-my-pi/pi-coding-agent 17.1.5 â 17.1.7
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/CHANGELOG.md +54 -0
- package/dist/{CHANGELOG-qs3vd6xf.md â CHANGELOG-5k4dq4g6.md} +54 -0
- package/dist/cli.js +3342 -3274
- package/dist/types/capability/index.d.ts +1 -1
- package/dist/types/capability/types.d.ts +23 -1
- package/dist/types/config/settings-schema.d.ts +39 -2
- package/dist/types/cursor.d.ts +2 -1
- package/dist/types/extensibility/extensions/runner.d.ts +4 -0
- package/dist/types/extensibility/shared-events.d.ts +18 -1
- package/dist/types/internal-urls/mcp-protocol.d.ts +3 -2
- package/dist/types/internal-urls/parse.d.ts +12 -0
- package/dist/types/internal-urls/router.d.ts +6 -0
- package/dist/types/internal-urls/types.d.ts +6 -0
- package/dist/types/lsp/config.d.ts +1 -0
- package/dist/types/lsp/types.d.ts +2 -0
- package/dist/types/mcp/manager.d.ts +5 -0
- package/dist/types/mcp/tool-bridge.d.ts +13 -0
- package/dist/types/modes/components/custom-editor.d.ts +5 -0
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-mode.d.ts +2 -0
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/session/agent-session-types.d.ts +8 -6
- package/dist/types/session/agent-session.d.ts +28 -1
- package/dist/types/session/model-controls.d.ts +4 -1
- package/dist/types/session/session-advisors.d.ts +7 -1
- package/dist/types/session/session-tools.d.ts +44 -6
- package/dist/types/session/streaming-output.d.ts +7 -2
- package/dist/types/session/tool-choice-queue.d.ts +6 -4
- package/dist/types/session/turn-recovery.d.ts +5 -3
- package/dist/types/task/index.d.ts +1 -1
- package/dist/types/task/types.d.ts +3 -11
- package/dist/types/thinking.d.ts +21 -2
- package/dist/types/tools/index.d.ts +8 -3
- package/dist/types/tools/output-meta.d.ts +5 -0
- package/dist/types/tools/read.d.ts +9 -1
- package/dist/types/tools/xdev.d.ts +53 -67
- package/dist/types/utils/cpuprofile.d.ts +51 -0
- package/dist/types/utils/inspect-image-mode.d.ts +29 -0
- package/dist/types/utils/profile-tree.d.ts +47 -0
- package/dist/types/utils/sample-profile.d.ts +67 -0
- package/dist/types/utils/title-generator.d.ts +17 -16
- package/package.json +12 -12
- package/src/capability/index.ts +43 -12
- package/src/capability/mcp.ts +21 -0
- package/src/capability/types.ts +20 -1
- package/src/cli/read-cli.ts +44 -2
- package/src/config/settings-schema.ts +42 -2
- package/src/config/settings.ts +35 -0
- package/src/cursor.ts +4 -3
- package/src/discovery/builtin-rules/index.ts +2 -0
- package/src/discovery/builtin-rules/ts-no-local-is-record.md +48 -0
- package/src/eval/py/runner.py +16 -2
- package/src/extensibility/extensions/runner.ts +117 -5
- package/src/extensibility/extensions/types.ts +0 -1
- package/src/extensibility/extensions/wrapper.ts +74 -42
- package/src/extensibility/hooks/tool-wrapper.ts +11 -4
- package/src/extensibility/hooks/types.ts +0 -1
- package/src/extensibility/shared-events.ts +18 -1
- package/src/internal-urls/mcp-protocol.ts +17 -3
- package/src/internal-urls/parse.ts +31 -0
- package/src/internal-urls/router.ts +24 -4
- package/src/internal-urls/types.ts +6 -0
- package/src/live/transport.ts +2 -2
- package/src/lsp/client.ts +2 -2
- package/src/lsp/config.ts +4 -0
- package/src/lsp/types.ts +2 -0
- package/src/mcp/config.ts +26 -14
- package/src/mcp/manager.ts +26 -9
- package/src/mcp/tool-bridge.ts +52 -1
- package/src/memories/index.ts +25 -6
- package/src/modes/components/custom-editor.ts +39 -16
- package/src/modes/components/status-line/segments.ts +3 -1
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/tool-execution.ts +8 -7
- package/src/modes/controllers/command-controller.ts +10 -10
- package/src/modes/controllers/extension-ui-controller.ts +7 -7
- package/src/modes/controllers/selector-controller.ts +7 -2
- package/src/modes/rpc/rpc-mode.ts +60 -47
- package/src/prompts/steering/user-interjection.md +2 -5
- package/src/prompts/tools/task.md +4 -2
- package/src/sdk.ts +64 -58
- package/src/session/agent-session-types.ts +8 -5
- package/src/session/agent-session.ts +144 -11
- package/src/session/model-controls.ts +48 -12
- package/src/session/session-advisors.ts +30 -14
- package/src/session/session-listing.ts +66 -4
- package/src/session/session-tools.ts +162 -54
- package/src/session/streaming-output.ts +18 -6
- package/src/session/tool-choice-queue.ts +19 -4
- package/src/session/turn-recovery.ts +25 -6
- package/src/slash-commands/builtin-registry.ts +69 -0
- package/src/task/executor.ts +11 -3
- package/src/task/index.ts +43 -32
- package/src/task/types.ts +12 -17
- package/src/thinking.ts +68 -5
- package/src/tools/bash.ts +16 -9
- package/src/tools/index.ts +36 -16
- package/src/tools/output-meta.ts +20 -0
- package/src/tools/read.ts +89 -15
- package/src/tools/write.ts +16 -7
- package/src/tools/xdev.ts +198 -210
- package/src/utils/cpuprofile.ts +235 -0
- package/src/utils/inspect-image-mode.ts +39 -0
- package/src/utils/profile-tree.ts +111 -0
- package/src/utils/sample-profile.ts +437 -0
- package/src/utils/title-generator.ts +88 -34
- package/dist/types/advisor/__tests__/advisor.test.d.ts +0 -1
- package/dist/types/advisor/__tests__/config.test.d.ts +0 -1
- package/dist/types/advisor/__tests__/emission-guard.test.d.ts +0 -1
- package/dist/types/cli/__tests__/auth-gateway-catalog.test.d.ts +0 -1
- package/dist/types/cli/update-cli.test.d.ts +0 -1
- package/dist/types/config/__tests__/model-registry.test.d.ts +0 -1
- package/dist/types/eval/__tests__/agent-bridge.test.d.ts +0 -1
- package/dist/types/eval/__tests__/bridge-timeout.test.d.ts +0 -1
- package/dist/types/eval/__tests__/budget-bridge.test.d.ts +0 -1
- package/dist/types/eval/__tests__/completion-bridge.test.d.ts +0 -1
- package/dist/types/eval/__tests__/helpers-local-roots.test.d.ts +0 -1
- package/dist/types/eval/__tests__/idle-timeout.test.d.ts +0 -1
- package/dist/types/eval/__tests__/js-context-manager.test.d.ts +0 -1
- package/dist/types/eval/__tests__/julia-prelude.test.d.ts +0 -1
- package/dist/types/eval/__tests__/kernel-spawn.test.d.ts +0 -1
- package/dist/types/eval/__tests__/prelude-agent.test.d.ts +0 -1
- package/dist/types/eval/__tests__/process-entry-import.test.d.ts +0 -1
- package/dist/types/eval/py/__tests__/prelude.test.d.ts +0 -1
- package/dist/types/eval/py/__tests__/runner-shell-output.test.d.ts +0 -1
- package/dist/types/hindsight/client.test.d.ts +0 -1
- package/dist/types/internal-urls/__tests__/agent-protocol-nested.test.d.ts +0 -1
- package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +0 -1
- package/dist/types/launch/broker-list-order.test.d.ts +0 -1
- package/dist/types/launch/broker-output-snapshot.test.d.ts +0 -1
- package/dist/types/launch/protocol.test.d.ts +0 -1
- package/dist/types/launch/spawn-options.test.d.ts +0 -1
- package/dist/types/launch/terminal-output.test.d.ts +0 -1
- package/dist/types/live/protocol.test.d.ts +0 -1
- package/dist/types/mcp/config-writer.test.d.ts +0 -1
- package/dist/types/mcp/smithery-auth.test.d.ts +0 -1
- package/dist/types/mcp/smithery-registry.test.d.ts +0 -1
- package/dist/types/mcp/transports/stdio.test.d.ts +0 -1
- package/dist/types/modes/components/__tests__/dynamic-border.test.d.ts +0 -1
- package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +0 -1
- package/dist/types/modes/components/__tests__/pause-screen.test.d.ts +0 -1
- package/dist/types/modes/components/__tests__/skill-message.test.d.ts +0 -1
- package/dist/types/modes/components/custom-editor-plugin-ctor.test.d.ts +0 -1
- package/dist/types/modes/components/custom-editor.test.d.ts +0 -1
- package/dist/types/modes/components/login-dialog.test.d.ts +0 -1
- package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +0 -1
- package/dist/types/modes/components/status-line/component.test.d.ts +0 -1
- package/dist/types/modes/components/tool-execution.test.d.ts +0 -1
- package/dist/types/modes/controllers/extension-ui-controller.test.d.ts +0 -1
- package/dist/types/modes/noninteractive-dispose.test.d.ts +0 -1
- package/dist/types/modes/print-mode.test.d.ts +0 -1
- package/dist/types/modes/session-teardown.test.d.ts +0 -1
- package/dist/types/modes/theme/mermaid-rendering.test.d.ts +0 -1
- package/dist/types/modes/utils/transcript-render-helpers.test.d.ts +0 -1
- package/dist/types/modes/warp-events.test.d.ts +0 -1
- package/dist/types/plan-mode/approved-plan-prompt.test.d.ts +0 -1
- package/dist/types/plan-mode/model-transition.test.d.ts +0 -1
- package/dist/types/plan-mode/reentry-prompt.test.d.ts +0 -1
- package/dist/types/session/agent-session-error-log.test.d.ts +0 -1
- package/dist/types/session/blob-store.test.d.ts +0 -1
- package/dist/types/session/messages.test.d.ts +0 -1
- package/dist/types/session/session-context.test.d.ts +0 -1
- package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +0 -1
- package/dist/types/ssh/__tests__/connection-manager-timeout.test.d.ts +0 -1
- package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +0 -1
- package/dist/types/ssh/__tests__/sshfs-mount.test.d.ts +0 -1
- package/dist/types/system-prompt.test.d.ts +0 -1
- package/dist/types/task/render.test.d.ts +0 -1
- package/dist/types/task/spawn-policy.test.d.ts +0 -1
- package/dist/types/tools/__tests__/eval-description.test.d.ts +0 -1
- package/dist/types/tools/__tests__/glob.test.d.ts +0 -1
- package/dist/types/tools/__tests__/json-tree.test.d.ts +0 -1
- package/dist/types/tools/__tests__/vibe-render.test.d.ts +0 -1
- package/dist/types/tools/hub/launch-compat.test.d.ts +0 -1
- package/dist/types/vibe/__tests__/token-rate.test.d.ts +0 -1
- package/src/advisor/__tests__/advisor.test.ts +0 -4889
- package/src/advisor/__tests__/config.test.ts +0 -349
- package/src/advisor/__tests__/emission-guard.test.ts +0 -147
- package/src/cli/__tests__/auth-gateway-catalog.test.ts +0 -111
- package/src/cli/update-cli.test.ts +0 -28
- package/src/config/__tests__/model-registry.test.ts +0 -182
- package/src/eval/__tests__/agent-bridge.test.ts +0 -1509
- package/src/eval/__tests__/bridge-timeout.test.ts +0 -170
- package/src/eval/__tests__/budget-bridge.test.ts +0 -80
- package/src/eval/__tests__/completion-bridge.test.ts +0 -412
- package/src/eval/__tests__/helpers-local-roots.test.ts +0 -55
- package/src/eval/__tests__/idle-timeout.test.ts +0 -80
- package/src/eval/__tests__/js-context-manager.test.ts +0 -456
- package/src/eval/__tests__/julia-prelude.test.ts +0 -66
- package/src/eval/__tests__/kernel-spawn.test.ts +0 -115
- package/src/eval/__tests__/prelude-agent.test.ts +0 -156
- package/src/eval/__tests__/process-entry-import.test.ts +0 -137
- package/src/eval/py/__tests__/prelude.test.ts +0 -104
- package/src/eval/py/__tests__/runner-shell-output.test.ts +0 -157
- package/src/hindsight/client.test.ts +0 -75
- package/src/internal-urls/__tests__/agent-protocol-nested.test.ts +0 -141
- package/src/internal-urls/__tests__/ssh-protocol.test.ts +0 -331
- package/src/launch/broker-list-order.test.ts +0 -89
- package/src/launch/broker-output-snapshot.test.ts +0 -126
- package/src/launch/protocol.test.ts +0 -59
- package/src/launch/spawn-options.test.ts +0 -31
- package/src/launch/terminal-output.test.ts +0 -107
- package/src/live/protocol.test.ts +0 -140
- package/src/mcp/config-writer.test.ts +0 -43
- package/src/mcp/smithery-auth.test.ts +0 -29
- package/src/mcp/smithery-registry.test.ts +0 -51
- package/src/mcp/transports/stdio.test.ts +0 -427
- package/src/modes/components/__tests__/dynamic-border.test.ts +0 -55
- package/src/modes/components/__tests__/move-overlay.test.ts +0 -252
- package/src/modes/components/__tests__/pause-screen.test.ts +0 -143
- package/src/modes/components/__tests__/skill-message.test.ts +0 -94
- package/src/modes/components/custom-editor-plugin-ctor.test.ts +0 -36
- package/src/modes/components/custom-editor.test.ts +0 -510
- package/src/modes/components/login-dialog.test.ts +0 -56
- package/src/modes/components/status-line/component.jj-cache.test.ts +0 -229
- package/src/modes/components/status-line/component.test.ts +0 -84
- package/src/modes/components/tool-execution.test.ts +0 -162
- package/src/modes/controllers/extension-ui-controller.test.ts +0 -250
- package/src/modes/noninteractive-dispose.test.ts +0 -73
- package/src/modes/print-mode.test.ts +0 -71
- package/src/modes/session-teardown.test.ts +0 -219
- package/src/modes/theme/mermaid-rendering.test.ts +0 -53
- package/src/modes/utils/transcript-render-helpers.test.ts +0 -38
- package/src/modes/warp-events.test.ts +0 -794
- package/src/plan-mode/approved-plan-prompt.test.ts +0 -36
- package/src/plan-mode/model-transition.test.ts +0 -60
- package/src/plan-mode/reentry-prompt.test.ts +0 -41
- package/src/session/agent-session-error-log.test.ts +0 -59
- package/src/session/blob-store.test.ts +0 -56
- package/src/session/messages.test.ts +0 -282
- package/src/session/session-context.test.ts +0 -384
- package/src/ssh/__tests__/connection-manager-args.test.ts +0 -191
- package/src/ssh/__tests__/connection-manager-timeout.test.ts +0 -61
- package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +0 -105
- package/src/ssh/__tests__/sshfs-mount.test.ts +0 -13
- package/src/system-prompt.test.ts +0 -236
- package/src/task/render.test.ts +0 -290
- package/src/task/spawn-policy.test.ts +0 -62
- package/src/tools/__tests__/eval-description.test.ts +0 -18
- package/src/tools/__tests__/glob.test.ts +0 -37
- package/src/tools/__tests__/json-tree.test.ts +0 -35
- package/src/tools/__tests__/vibe-render.test.ts +0 -210
- package/src/tools/hub/launch-compat.test.ts +0 -40
- package/src/vibe/__tests__/token-rate.test.ts +0 -96
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "bun:test";
|
|
2
|
-
import * as fs from "node:fs/promises";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
import { TempDir } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import { startDaemonBrokerFromEnvironment } from "./broker";
|
|
6
|
-
import { createDaemonBrokerClient } from "./client";
|
|
7
|
-
import {
|
|
8
|
-
DAEMON_IDLE_GRACE_ENV,
|
|
9
|
-
DAEMON_PROJECT_DIR_ENV,
|
|
10
|
-
DAEMON_RUNTIME_DIR_ENV,
|
|
11
|
-
type DaemonOperation,
|
|
12
|
-
} from "./protocol";
|
|
13
|
-
import * as terminalOutput from "./terminal-output";
|
|
14
|
-
|
|
15
|
-
function restoreEnv(name: string, value: string | undefined): void {
|
|
16
|
-
if (value === undefined) delete process.env[name];
|
|
17
|
-
else process.env[name] = value;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe("daemon broker log snapshots", () => {
|
|
21
|
-
it("returns the cursor captured with the PTY bytes rendered in the response", async () => {
|
|
22
|
-
using tempDir = TempDir.createSync("@omp-launch-cursor-");
|
|
23
|
-
const projectDir = path.join(tempDir.path(), "project");
|
|
24
|
-
const runtimeDir = path.join(tempDir.path(), "runtime");
|
|
25
|
-
await fs.mkdir(projectDir);
|
|
26
|
-
const scriptPath = path.join(projectDir, "service.ts");
|
|
27
|
-
await Bun.write(
|
|
28
|
-
scriptPath,
|
|
29
|
-
`process.stdin.setEncoding("utf8");
|
|
30
|
-
process.stdin.resume();
|
|
31
|
-
process.stdout.write("READY\\n");
|
|
32
|
-
process.stdin.on("data", () => process.stdout.write("AFTER-SNAPSHOT\\n"));
|
|
33
|
-
`,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
const client = await createDaemonBrokerClient(projectDir, { runtimeDir, idleGraceMs: 5_000 });
|
|
37
|
-
const renderStarted = Promise.withResolvers<void>();
|
|
38
|
-
const releaseRender = Promise.withResolvers<void>();
|
|
39
|
-
const renderTerminalOutput = terminalOutput.renderTerminalOutput;
|
|
40
|
-
vi.spyOn(terminalOutput, "renderTerminalOutput").mockImplementation(async (output, options) => {
|
|
41
|
-
renderStarted.resolve();
|
|
42
|
-
await releaseRender.promise;
|
|
43
|
-
return renderTerminalOutput(output, options);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const previousProjectDir = process.env[DAEMON_PROJECT_DIR_ENV];
|
|
47
|
-
const previousRuntimeDir = process.env[DAEMON_RUNTIME_DIR_ENV];
|
|
48
|
-
const previousGrace = process.env[DAEMON_IDLE_GRACE_ENV];
|
|
49
|
-
const previousTitle = process.title;
|
|
50
|
-
process.env[DAEMON_PROJECT_DIR_ENV] = projectDir;
|
|
51
|
-
process.env[DAEMON_RUNTIME_DIR_ENV] = runtimeDir;
|
|
52
|
-
process.env[DAEMON_IDLE_GRACE_ENV] = "5000";
|
|
53
|
-
const broker = startDaemonBrokerFromEnvironment();
|
|
54
|
-
restoreEnv(DAEMON_PROJECT_DIR_ENV, previousProjectDir);
|
|
55
|
-
restoreEnv(DAEMON_RUNTIME_DIR_ENV, previousRuntimeDir);
|
|
56
|
-
restoreEnv(DAEMON_IDLE_GRACE_ENV, previousGrace);
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
const started = await client.request({
|
|
60
|
-
op: "start",
|
|
61
|
-
spec: {
|
|
62
|
-
name: "cursor",
|
|
63
|
-
application: process.execPath,
|
|
64
|
-
args: [scriptPath],
|
|
65
|
-
env: {},
|
|
66
|
-
cwd: projectDir,
|
|
67
|
-
pty: true,
|
|
68
|
-
ready: { log: "READY", timeoutMs: 5_000 },
|
|
69
|
-
restart: "no",
|
|
70
|
-
persist: false,
|
|
71
|
-
detached: false,
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
if (started.op !== "start") throw new Error("unexpected start result");
|
|
75
|
-
expect(started.readyTimedOut).toBeFalse();
|
|
76
|
-
|
|
77
|
-
const snapshotPromise = client.request({
|
|
78
|
-
op: "logs",
|
|
79
|
-
name: "cursor",
|
|
80
|
-
lines: 20,
|
|
81
|
-
head: false,
|
|
82
|
-
follow: false,
|
|
83
|
-
timeoutMs: 1_000,
|
|
84
|
-
renderTerminalRows: true,
|
|
85
|
-
} as DaemonOperation);
|
|
86
|
-
await renderStarted.promise;
|
|
87
|
-
await client.request({ op: "send", name: "cursor", data: "race\r" });
|
|
88
|
-
const observed = await client.request({
|
|
89
|
-
op: "wait",
|
|
90
|
-
name: "cursor",
|
|
91
|
-
for: "exit",
|
|
92
|
-
pattern: "AFTER-SNAPSHOT",
|
|
93
|
-
timeoutMs: 1_000,
|
|
94
|
-
});
|
|
95
|
-
if (observed.op !== "wait") throw new Error("unexpected wait result");
|
|
96
|
-
expect(observed.timedOut).toBeFalse();
|
|
97
|
-
releaseRender.resolve();
|
|
98
|
-
|
|
99
|
-
const snapshot = await snapshotPromise;
|
|
100
|
-
if (snapshot.op !== "logs") throw new Error("unexpected logs result");
|
|
101
|
-
expect(snapshot.terminalRows?.join("\n")).not.toContain("AFTER-SNAPSHOT");
|
|
102
|
-
|
|
103
|
-
const followed = await client.request({
|
|
104
|
-
op: "logs",
|
|
105
|
-
name: "cursor",
|
|
106
|
-
lines: 20,
|
|
107
|
-
head: false,
|
|
108
|
-
follow: true,
|
|
109
|
-
cursor: snapshot.cursor,
|
|
110
|
-
timeoutMs: 1_000,
|
|
111
|
-
renderTerminalRows: true,
|
|
112
|
-
} as DaemonOperation);
|
|
113
|
-
if (followed.op !== "logs") throw new Error("unexpected follow result");
|
|
114
|
-
expect(followed.timedOut).toBeFalse();
|
|
115
|
-
expect(followed.text).toContain("AFTER-SNAPSHOT");
|
|
116
|
-
} finally {
|
|
117
|
-
releaseRender.resolve();
|
|
118
|
-
await client.request({ op: "stop", name: "cursor", timeoutMs: 2_000 }).catch(() => undefined);
|
|
119
|
-
await client.request({ op: "shutdown" }).catch(() => undefined);
|
|
120
|
-
client.close();
|
|
121
|
-
await broker;
|
|
122
|
-
process.title = previousTitle;
|
|
123
|
-
vi.restoreAllMocks();
|
|
124
|
-
}
|
|
125
|
-
}, 20_000);
|
|
126
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { type DaemonOperation, parseDaemonRpcResult, parseDaemonWireRequest } from "./protocol";
|
|
3
|
-
|
|
4
|
-
const operation: Extract<DaemonOperation, { op: "logs" }> = {
|
|
5
|
-
op: "logs",
|
|
6
|
-
name: "web",
|
|
7
|
-
lines: 20,
|
|
8
|
-
head: false,
|
|
9
|
-
follow: false,
|
|
10
|
-
timeoutMs: 1_000,
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const baseResult = {
|
|
14
|
-
name: "web",
|
|
15
|
-
text: "ready",
|
|
16
|
-
cursor: 42,
|
|
17
|
-
timedOut: false,
|
|
18
|
-
state: "running" as const,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
describe("launch logs protocol", () => {
|
|
22
|
-
it("decodes terminal rows without changing their bytes", () => {
|
|
23
|
-
const terminalRows = ["\x1b[0m\x1b[1;38;5;2mready", "", "çe\u0301"];
|
|
24
|
-
expect(parseDaemonRpcResult(operation, { ...baseResult, terminalRows })).toEqual({
|
|
25
|
-
op: "logs",
|
|
26
|
-
...baseResult,
|
|
27
|
-
terminalRows,
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("rejects a non-array terminal row payload", () => {
|
|
32
|
-
expect(() => parseDaemonRpcResult(operation, { ...baseResult, terminalRows: "ready" })).toThrow(
|
|
33
|
-
"result.terminalRows must be an array of strings",
|
|
34
|
-
);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("rejects non-string terminal row entries", () => {
|
|
38
|
-
expect(() => parseDaemonRpcResult(operation, { ...baseResult, terminalRows: ["ready", 7] })).toThrow(
|
|
39
|
-
"result.terminalRows item must be a string",
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe("launch logs compatibility", () => {
|
|
45
|
-
it("preserves the rendered-row request for upgraded brokers", () => {
|
|
46
|
-
const request = parseDaemonWireRequest({
|
|
47
|
-
id: "request-1",
|
|
48
|
-
token: "token-1",
|
|
49
|
-
operation: { ...operation, renderTerminalRows: true },
|
|
50
|
-
});
|
|
51
|
-
expect(request.operation).toMatchObject({ ...operation, renderTerminalRows: true });
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("decodes raw terminal text from an already-running legacy broker", () => {
|
|
55
|
-
const result = parseDaemonRpcResult(operation, { ...baseResult, terminalText: "progress\rready" });
|
|
56
|
-
if (result.op !== "logs") throw new Error("unexpected result");
|
|
57
|
-
expect("terminalText" in result ? result.terminalText : undefined).toBe("progress\rready");
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { resolveDaemonSpawnOptions } from "./spawn-options";
|
|
3
|
-
|
|
4
|
-
describe("resolveDaemonSpawnOptions", () => {
|
|
5
|
-
it("hides Windows daemons when the host has no console", () => {
|
|
6
|
-
expect(
|
|
7
|
-
resolveDaemonSpawnOptions({
|
|
8
|
-
platform: "win32",
|
|
9
|
-
hostHasInheritableConsole: false,
|
|
10
|
-
}),
|
|
11
|
-
).toEqual({ detached: false, windowsHide: true });
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("inherits the Windows host console instead of detaching", () => {
|
|
15
|
-
expect(
|
|
16
|
-
resolveDaemonSpawnOptions({
|
|
17
|
-
platform: "win32",
|
|
18
|
-
hostHasInheritableConsole: true,
|
|
19
|
-
}),
|
|
20
|
-
).toEqual({ detached: false, windowsHide: false });
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("keeps POSIX daemons in their own session", () => {
|
|
24
|
-
expect(
|
|
25
|
-
resolveDaemonSpawnOptions({
|
|
26
|
-
platform: "linux",
|
|
27
|
-
hostHasInheritableConsole: false,
|
|
28
|
-
}),
|
|
29
|
-
).toEqual({ detached: true });
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { renderTerminalOutput } from "./terminal-output";
|
|
3
|
-
|
|
4
|
-
const RESET = "\x1b[0m";
|
|
5
|
-
|
|
6
|
-
interface TerminalCase {
|
|
7
|
-
name: string;
|
|
8
|
-
input: string;
|
|
9
|
-
expected: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const cases: TerminalCase[] = [
|
|
13
|
-
{
|
|
14
|
-
name: "overwrites the current row after carriage return",
|
|
15
|
-
input: "progress 10%\rDONE",
|
|
16
|
-
expected: [`${RESET}DONEress 10%`],
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
name: "honors absolute and relative horizontal cursor movement",
|
|
20
|
-
input: "abcdef\x1b[3GZ\x1b[2CX",
|
|
21
|
-
expected: [`${RESET}abZdeX`],
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: "honors absolute and relative vertical cursor movement",
|
|
25
|
-
input: "one\r\ntwo\r\nthree\x1b[2A\x1b[1GONE\x1b[1B\x1b[2D]",
|
|
26
|
-
expected: [`${RESET}ONE`, `${RESET}t]o`, `${RESET}three`],
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
name: "honors absolute cursor positioning",
|
|
30
|
-
input: "abc\r\ndef\x1b[1;2HZ",
|
|
31
|
-
expected: [`${RESET}aZc`, `${RESET}def`],
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
name: "erases from the cursor through the row",
|
|
35
|
-
input: "abcdef\r\x1b[3C\x1b[K",
|
|
36
|
-
expected: [`${RESET}abc`],
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: "inserts characters without losing shifted content",
|
|
40
|
-
input: "abcdef\r\x1b[3C\x1b[2@XY",
|
|
41
|
-
expected: [`${RESET}abcXYdef`],
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: "deletes characters and closes the gap",
|
|
45
|
-
input: "abcdef\r\x1b[2C\x1b[2P",
|
|
46
|
-
expected: [`${RESET}abef`],
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: "inserts a terminal row",
|
|
50
|
-
input: "one\r\ntwo\r\nthree\x1b[2;1H\x1b[Linserted",
|
|
51
|
-
expected: [`${RESET}one`, `${RESET}inserted`, `${RESET}two`, `${RESET}three`],
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: "deletes a terminal row",
|
|
55
|
-
input: "one\r\ntwo\r\nthree\x1b[2;1H\x1b[M",
|
|
56
|
-
expected: [`${RESET}one`, `${RESET}three`],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: "wraps at the fixed 120-column PTY width",
|
|
60
|
-
input: `${"a".repeat(120)}b`,
|
|
61
|
-
expected: [`${RESET}${"a".repeat(120)}`, `${RESET}b`],
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: "preserves wide and combining characters",
|
|
65
|
-
input: "Açe\u0301B",
|
|
66
|
-
expected: [`${RESET}Açe\u0301B`],
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: "canonicalizes color, reset, and text decorations",
|
|
70
|
-
input: "\x1b[1;2;3;4;7;9;53;38;2;1;2;3;48;5;17mX\x1b[0mY",
|
|
71
|
-
expected: [`${RESET}\x1b[1;2;3;4;7;9;53;38;2;1;2;3;48;5;17mX${RESET}Y`],
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: "restores the normal buffer after alternate-buffer output",
|
|
75
|
-
input: "main\x1b[?1049hALT\x1b[?1049l",
|
|
76
|
-
expected: [`${RESET}main`],
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "keeps internal blank rows while trimming blank rows and spaces at the end",
|
|
80
|
-
input: "alpha \r\n\r\nomega \r\n\r\n",
|
|
81
|
-
expected: [`${RESET}alpha`, "", `${RESET}omega`],
|
|
82
|
-
},
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
describe("renderTerminalOutput", () => {
|
|
86
|
-
for (const testCase of cases) {
|
|
87
|
-
it(testCase.name, async () => {
|
|
88
|
-
expect(await renderTerminalOutput(testCase.input, { head: false, maxRows: 100 })).toEqual(testCase.expected);
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
it("returns an empty row set for empty output", async () => {
|
|
93
|
-
expect(await renderTerminalOutput("", { head: false, maxRows: 100 })).toEqual([]);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("applies head and tail row limits after replaying scrollback", async () => {
|
|
97
|
-
const output = Array.from({ length: 4_200 }, (_, index) => `row-${index}`).join("\r\n");
|
|
98
|
-
expect(await renderTerminalOutput(output, { head: true, maxRows: 2 })).toEqual([
|
|
99
|
-
`${RESET}row-64`,
|
|
100
|
-
`${RESET}row-65`,
|
|
101
|
-
]);
|
|
102
|
-
expect(await renderTerminalOutput(output, { head: false, maxRows: 2 })).toEqual([
|
|
103
|
-
`${RESET}row-4198`,
|
|
104
|
-
`${RESET}row-4199`,
|
|
105
|
-
]);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
3
|
-
buildDelegationContextAppend,
|
|
4
|
-
buildLiveSessionPayload,
|
|
5
|
-
buildSessionClose,
|
|
6
|
-
buildSessionContextAppend,
|
|
7
|
-
CONTEXT_CHUNK_BYTES,
|
|
8
|
-
chunkLiveContext,
|
|
9
|
-
LIVE_MODEL,
|
|
10
|
-
parseLiveServerEvent,
|
|
11
|
-
} from "./protocol";
|
|
12
|
-
|
|
13
|
-
describe("Frameless Bidi server events", () => {
|
|
14
|
-
test("parses a client delegation and keeps only input text content", () => {
|
|
15
|
-
const event = parseLiveServerEvent(
|
|
16
|
-
JSON.stringify({
|
|
17
|
-
type: "delegation.created",
|
|
18
|
-
item: {
|
|
19
|
-
type: "delegation",
|
|
20
|
-
target: "client",
|
|
21
|
-
id: "delegation-7",
|
|
22
|
-
content: [
|
|
23
|
-
{ type: "input_text", text: "Inspect the failing build. " },
|
|
24
|
-
{ type: "output_text", text: "ignored" },
|
|
25
|
-
{ type: "input_text", text: "Repair the root cause." },
|
|
26
|
-
],
|
|
27
|
-
},
|
|
28
|
-
}),
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
expect(event).toEqual({
|
|
32
|
-
type: "delegation.created",
|
|
33
|
-
item: {
|
|
34
|
-
type: "delegation",
|
|
35
|
-
target: "client",
|
|
36
|
-
id: "delegation-7",
|
|
37
|
-
content: [
|
|
38
|
-
{ type: "input_text", text: "Inspect the failing build. " },
|
|
39
|
-
{ type: "input_text", text: "Repair the root cause." },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("parses input and output transcript deltas", () => {
|
|
46
|
-
expect(parseLiveServerEvent({ type: "input_transcript.added", item: { text: "What changed?" } })).toEqual({
|
|
47
|
-
type: "input_transcript.added",
|
|
48
|
-
item: { text: "What changed?" },
|
|
49
|
-
});
|
|
50
|
-
expect(parseLiveServerEvent({ type: "output_transcript.added", item: { text: "I will inspect it." } })).toEqual({
|
|
51
|
-
type: "output_transcript.added",
|
|
52
|
-
item: { text: "I will inspect it." },
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("parses completed user and assistant turns", () => {
|
|
57
|
-
expect(
|
|
58
|
-
parseLiveServerEvent({ type: "turn.done", turn: { role: "user", transcript: "Run the checks." } }),
|
|
59
|
-
).toEqual({ type: "turn.done", turn: { role: "user", transcript: "Run the checks." } });
|
|
60
|
-
expect(
|
|
61
|
-
parseLiveServerEvent({
|
|
62
|
-
type: "turn.done",
|
|
63
|
-
turn: { role: "assistant", transcript: "The checks pass." },
|
|
64
|
-
}),
|
|
65
|
-
).toEqual({ type: "turn.done", turn: { role: "assistant", transcript: "The checks pass." } });
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("parses an output audio delta", () => {
|
|
69
|
-
expect(parseLiveServerEvent('{"type":"output_audio.delta","audio":"AAECAw=="}')).toEqual({
|
|
70
|
-
type: "output_audio.delta",
|
|
71
|
-
audio: "AAECAw==",
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("extracts top-level and nested error messages", () => {
|
|
76
|
-
expect(parseLiveServerEvent({ type: "error", message: "call expired" })).toEqual({
|
|
77
|
-
type: "error",
|
|
78
|
-
message: "call expired",
|
|
79
|
-
});
|
|
80
|
-
expect(parseLiveServerEvent({ type: "error", error: { message: "media rejected", code: "bad_media" } })).toEqual({
|
|
81
|
-
type: "error",
|
|
82
|
-
message: "media rejected",
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("classifies unsupported events and rejects malformed known events", () => {
|
|
87
|
-
expect(parseLiveServerEvent({ type: "rate_limits.updated", remaining: 3 })).toEqual({
|
|
88
|
-
type: "unknown",
|
|
89
|
-
wireType: "rate_limits.updated",
|
|
90
|
-
});
|
|
91
|
-
expect(parseLiveServerEvent({ type: "output_audio.delta", audio: 12 })).toBeNull();
|
|
92
|
-
expect(parseLiveServerEvent({ type: "turn.done", turn: { role: "tool", transcript: "no" } })).toBeNull();
|
|
93
|
-
expect(parseLiveServerEvent("not json")).toBeNull();
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe("Frameless Bidi client payloads", () => {
|
|
98
|
-
test("builds the exact live call session JSON", () => {
|
|
99
|
-
const payload = buildLiveSessionPayload("Be concise.", "marin");
|
|
100
|
-
|
|
101
|
-
expect(LIVE_MODEL).toBe("gpt-live-1-codex");
|
|
102
|
-
expect(JSON.stringify(payload)).toBe(
|
|
103
|
-
'{"model":"gpt-live-1-codex","instructions":"Be concise.","audio":{"output":{"voice":"marin"}},"delegation":{"type":"client"}}',
|
|
104
|
-
);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("builds the exact delegation context JSON", () => {
|
|
108
|
-
const message = buildDelegationContextAppend("delegation-7", "The tests now pass.", "commentary");
|
|
109
|
-
|
|
110
|
-
expect(JSON.stringify(message)).toBe(
|
|
111
|
-
'{"type":"delegation.context.append","delegation_item_id":"delegation-7","channel":"commentary","content":[{"type":"input_text","text":"The tests now pass."}]}',
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("omits optional channels and builds session close", () => {
|
|
116
|
-
expect(buildDelegationContextAppend("delegation-8", "Done.")).toEqual({
|
|
117
|
-
type: "delegation.context.append",
|
|
118
|
-
delegation_item_id: "delegation-8",
|
|
119
|
-
content: [{ type: "input_text", text: "Done." }],
|
|
120
|
-
});
|
|
121
|
-
expect(buildSessionContextAppend("Still investigating.", "speakable")).toEqual({
|
|
122
|
-
type: "session.context.append",
|
|
123
|
-
channel: "speakable",
|
|
124
|
-
content: [{ type: "input_text", text: "Still investigating." }],
|
|
125
|
-
});
|
|
126
|
-
expect(buildSessionClose()).toEqual({ type: "session.close" });
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("context chunks are UTF-8 safe, bounded, and perfectly reassemble", () => {
|
|
131
|
-
const text = `${"a".repeat(497)}đ${"Ê柢đ".repeat(180)}`;
|
|
132
|
-
const chunks = chunkLiveContext(text);
|
|
133
|
-
const encoder = new TextEncoder();
|
|
134
|
-
|
|
135
|
-
expect(chunks.length).toBeGreaterThan(1);
|
|
136
|
-
expect(chunks.join("")).toBe(text);
|
|
137
|
-
for (const chunk of chunks) {
|
|
138
|
-
expect(encoder.encode(chunk).byteLength).toBeLessThanOrEqual(CONTEXT_CHUNK_BYTES);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
-
import * as fs from "node:fs/promises";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
import * as path from "node:path";
|
|
5
|
-
import { addMCPServer, readDisabledServers, readMCPConfigFile, setServerDisabled } from "./config-writer";
|
|
6
|
-
|
|
7
|
-
describe("config-writer concurrent mutations", () => {
|
|
8
|
-
let dir: string;
|
|
9
|
-
let filePath: string;
|
|
10
|
-
|
|
11
|
-
beforeEach(async () => {
|
|
12
|
-
dir = await fs.mkdtemp(path.join(os.tmpdir(), "omp-mcp-config-"));
|
|
13
|
-
filePath = path.join(dir, "mcp.json");
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(async () => {
|
|
17
|
-
await fs.rm(dir, { recursive: true, force: true });
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("preserves both servers when two adds race the same file", async () => {
|
|
21
|
-
await Promise.all([
|
|
22
|
-
addMCPServer(filePath, "alpha", { type: "stdio", command: "a" }),
|
|
23
|
-
addMCPServer(filePath, "bravo", { type: "stdio", command: "b" }),
|
|
24
|
-
]);
|
|
25
|
-
|
|
26
|
-
const config = await readMCPConfigFile(filePath);
|
|
27
|
-
expect(Object.keys(config.mcpServers ?? {}).sort()).toEqual(["alpha", "bravo"]);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("preserves both denylist edits when disable calls race", async () => {
|
|
31
|
-
await Promise.all([setServerDisabled(filePath, "alpha", true), setServerDisabled(filePath, "bravo", true)]);
|
|
32
|
-
|
|
33
|
-
expect((await readDisabledServers(filePath)).sort()).toEqual(["alpha", "bravo"]);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("writes into a directory that does not exist yet", async () => {
|
|
37
|
-
const nestedPath = path.join(dir, "nested", "deep", "mcp.json");
|
|
38
|
-
await addMCPServer(nestedPath, "alpha", { type: "stdio", command: "a" });
|
|
39
|
-
|
|
40
|
-
const config = await readMCPConfigFile(nestedPath);
|
|
41
|
-
expect(Object.keys(config.mcpServers ?? {})).toEqual(["alpha"]);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from "bun:test";
|
|
2
|
-
import { pollSmitheryCliAuthSession } from "./smithery-auth";
|
|
3
|
-
|
|
4
|
-
type FetchInput = string | URL | Request;
|
|
5
|
-
type FetchInit = RequestInit | BunFetchRequestInit;
|
|
6
|
-
|
|
7
|
-
describe("pollSmitheryCliAuthSession fetch cancellation", () => {
|
|
8
|
-
afterEach(() => {
|
|
9
|
-
vi.restoreAllMocks();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it("bounds each poll request with a timeout abort signal even without a caller signal", async () => {
|
|
13
|
-
const signals: AbortSignal[] = [];
|
|
14
|
-
const fetchStub = Object.assign(
|
|
15
|
-
async (_input: FetchInput, init?: FetchInit) => {
|
|
16
|
-
if (init?.signal instanceof AbortSignal) signals.push(init.signal);
|
|
17
|
-
return Response.json({ status: "pending" });
|
|
18
|
-
},
|
|
19
|
-
{ preconnect: globalThis.fetch.preconnect },
|
|
20
|
-
);
|
|
21
|
-
vi.spyOn(globalThis, "fetch").mockImplementation(fetchStub);
|
|
22
|
-
|
|
23
|
-
const result = await pollSmitheryCliAuthSession("sess-123");
|
|
24
|
-
|
|
25
|
-
expect(result.status).toBe("pending");
|
|
26
|
-
expect(signals).toHaveLength(1);
|
|
27
|
-
expect(signals[0]?.aborted).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from "bun:test";
|
|
2
|
-
import { searchSmitheryRegistry } from "./smithery-registry";
|
|
3
|
-
|
|
4
|
-
type FetchInput = string | URL | Request;
|
|
5
|
-
type FetchInit = RequestInit | BunFetchRequestInit;
|
|
6
|
-
|
|
7
|
-
describe("searchSmitheryRegistry fetch cancellation", () => {
|
|
8
|
-
afterEach(() => {
|
|
9
|
-
vi.restoreAllMocks();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it("adds timeout signals to search and detail requests", async () => {
|
|
13
|
-
const signals: AbortSignal[] = [];
|
|
14
|
-
const fetchStub = Object.assign(
|
|
15
|
-
async (input: FetchInput, init?: FetchInit) => {
|
|
16
|
-
if (init?.signal instanceof AbortSignal) signals.push(init.signal);
|
|
17
|
-
const url = String(input);
|
|
18
|
-
if (url.includes("?")) {
|
|
19
|
-
return Response.json({
|
|
20
|
-
servers: [
|
|
21
|
-
{
|
|
22
|
-
id: "srv_1",
|
|
23
|
-
namespace: "smithery-ai",
|
|
24
|
-
slug: "filesystem",
|
|
25
|
-
qualifiedName: "@smithery-ai/filesystem",
|
|
26
|
-
displayName: "Filesystem",
|
|
27
|
-
description: "File access",
|
|
28
|
-
useCount: 1,
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
return Response.json({
|
|
34
|
-
qualifiedName: "@smithery-ai/filesystem",
|
|
35
|
-
displayName: "Filesystem",
|
|
36
|
-
description: "File access",
|
|
37
|
-
connections: [{ type: "http", deploymentUrl: "https://mcp.example" }],
|
|
38
|
-
tools: [],
|
|
39
|
-
});
|
|
40
|
-
},
|
|
41
|
-
{ preconnect: globalThis.fetch.preconnect },
|
|
42
|
-
);
|
|
43
|
-
vi.spyOn(globalThis, "fetch").mockImplementation(fetchStub);
|
|
44
|
-
|
|
45
|
-
const results = await searchSmitheryRegistry("filesystem", { limit: 1 });
|
|
46
|
-
|
|
47
|
-
expect(results[0]?.name).toBe("smithery-ai/filesystem");
|
|
48
|
-
expect(signals).toHaveLength(2);
|
|
49
|
-
expect(signals.every(signal => signal instanceof AbortSignal)).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
});
|