agent-mockingbird 0.0.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/.agents/skills/btca-cli/SKILL.md +64 -0
- package/.agents/skills/btca-cli/agents/openai.yaml +3 -0
- package/.agents/skills/frontend-design/SKILL.md +42 -0
- package/.agents/skills/frontend-design/agents/openai.yaml +3 -0
- package/.env.example +36 -0
- package/.githooks/pre-commit +33 -0
- package/.github/workflows/ci.yml +309 -0
- package/.opencode/bun.lock +18 -0
- package/.opencode/package.json +5 -0
- package/.opencode/tools/agent_type_manager.ts +100 -0
- package/.opencode/tools/config_manager.ts +87 -0
- package/.opencode/tools/cron_manager.ts +145 -0
- package/.opencode/tools/memory_get.ts +43 -0
- package/.opencode/tools/memory_remember.ts +53 -0
- package/.opencode/tools/memory_search.ts +48 -0
- package/AGENTS.md +126 -0
- package/MEMORY.md +2 -0
- package/README.md +451 -0
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/agent-mockingbird.config.example.json +135 -0
- package/apps/server/package.json +32 -0
- package/apps/server/src/backend/agents/bootstrapContext.ts +362 -0
- package/apps/server/src/backend/agents/openclawImport.test.ts +133 -0
- package/apps/server/src/backend/agents/openclawImport.ts +797 -0
- package/apps/server/src/backend/agents/opencodeConfig.ts +428 -0
- package/apps/server/src/backend/agents/service.ts +10 -0
- package/apps/server/src/backend/config/example-config.test.ts +20 -0
- package/apps/server/src/backend/config/orchestration.ts +243 -0
- package/apps/server/src/backend/config/policy.ts +158 -0
- package/apps/server/src/backend/config/schema.test.ts +15 -0
- package/apps/server/src/backend/config/schema.ts +391 -0
- package/apps/server/src/backend/config/semantic.test.ts +34 -0
- package/apps/server/src/backend/config/semantic.ts +149 -0
- package/apps/server/src/backend/config/service.test.ts +75 -0
- package/apps/server/src/backend/config/service.ts +207 -0
- package/apps/server/src/backend/config/smoke.ts +77 -0
- package/apps/server/src/backend/config/store.test.ts +123 -0
- package/apps/server/src/backend/config/store.ts +581 -0
- package/apps/server/src/backend/config/testFixtures.ts +5 -0
- package/apps/server/src/backend/config/types.ts +56 -0
- package/apps/server/src/backend/contracts/events.ts +320 -0
- package/apps/server/src/backend/contracts/runtime.ts +111 -0
- package/apps/server/src/backend/cron/executor.ts +435 -0
- package/apps/server/src/backend/cron/repository.ts +170 -0
- package/apps/server/src/backend/cron/service.ts +660 -0
- package/apps/server/src/backend/cron/storage.ts +92 -0
- package/apps/server/src/backend/cron/types.ts +138 -0
- package/apps/server/src/backend/cron/utils.ts +351 -0
- package/apps/server/src/backend/db/client.ts +20 -0
- package/apps/server/src/backend/db/migrate.ts +40 -0
- package/apps/server/src/backend/db/repository.ts +1762 -0
- package/apps/server/src/backend/db/schema.ts +113 -0
- package/apps/server/src/backend/db/usageDashboard.test.ts +102 -0
- package/apps/server/src/backend/db/wipe.ts +13 -0
- package/apps/server/src/backend/defaults.ts +32 -0
- package/apps/server/src/backend/env.ts +48 -0
- package/apps/server/src/backend/heartbeat/activeHours.ts +45 -0
- package/apps/server/src/backend/heartbeat/defaultJob.ts +88 -0
- package/apps/server/src/backend/heartbeat/heartbeat.test.ts +110 -0
- package/apps/server/src/backend/heartbeat/runtimeService.ts +190 -0
- package/apps/server/src/backend/heartbeat/service.ts +176 -0
- package/apps/server/src/backend/heartbeat/state.test.ts +63 -0
- package/apps/server/src/backend/heartbeat/state.ts +167 -0
- package/apps/server/src/backend/heartbeat/types.ts +54 -0
- package/apps/server/src/backend/http/boundedQueue.test.ts +49 -0
- package/apps/server/src/backend/http/boundedQueue.ts +92 -0
- package/apps/server/src/backend/http/parsers.ts +40 -0
- package/apps/server/src/backend/http/router.ts +61 -0
- package/apps/server/src/backend/http/routes/agentRoutes.ts +67 -0
- package/apps/server/src/backend/http/routes/backgroundRoutes.ts +203 -0
- package/apps/server/src/backend/http/routes/chatRoutes.ts +107 -0
- package/apps/server/src/backend/http/routes/configRoutes.ts +602 -0
- package/apps/server/src/backend/http/routes/cronRoutes.ts +221 -0
- package/apps/server/src/backend/http/routes/dashboardRoutes.ts +308 -0
- package/apps/server/src/backend/http/routes/eventRoutes.ts +7 -0
- package/apps/server/src/backend/http/routes/heartbeatRoutes.test.ts +41 -0
- package/apps/server/src/backend/http/routes/heartbeatRoutes.ts +28 -0
- package/apps/server/src/backend/http/routes/index.ts +101 -0
- package/apps/server/src/backend/http/routes/mcpRoutes.ts +213 -0
- package/apps/server/src/backend/http/routes/memoryRoutes.ts +154 -0
- package/apps/server/src/backend/http/routes/runRoutes.ts +310 -0
- package/apps/server/src/backend/http/routes/runtimeRoutes.ts +197 -0
- package/apps/server/src/backend/http/routes/skillRoutes.ts +112 -0
- package/apps/server/src/backend/http/routes/uiRoutes.test.ts +161 -0
- package/apps/server/src/backend/http/routes/uiRoutes.ts +177 -0
- package/apps/server/src/backend/http/routes/usageRoutes.test.ts +104 -0
- package/apps/server/src/backend/http/routes/usageRoutes.ts +767 -0
- package/apps/server/src/backend/http/schemas.ts +64 -0
- package/apps/server/src/backend/http/sse.ts +144 -0
- package/apps/server/src/backend/integration/backend-core.test.ts +2316 -0
- package/apps/server/src/backend/logging/logger.ts +64 -0
- package/apps/server/src/backend/mcp/service.ts +326 -0
- package/apps/server/src/backend/memory/cli.ts +170 -0
- package/apps/server/src/backend/memory/conceptExpansion.test.ts +28 -0
- package/apps/server/src/backend/memory/conceptExpansion.ts +80 -0
- package/apps/server/src/backend/memory/qmdPort.test.ts +54 -0
- package/apps/server/src/backend/memory/qmdPort.ts +61 -0
- package/apps/server/src/backend/memory/records.test.ts +66 -0
- package/apps/server/src/backend/memory/records.ts +229 -0
- package/apps/server/src/backend/memory/service.ts +2012 -0
- package/apps/server/src/backend/memory/sqliteVec.ts +58 -0
- package/apps/server/src/backend/memory/types.ts +104 -0
- package/apps/server/src/backend/opencode/agentMockingbirdPlugin.test.ts +396 -0
- package/apps/server/src/backend/opencode/client.ts +98 -0
- package/apps/server/src/backend/opencode/models.ts +41 -0
- package/apps/server/src/backend/opencode/systemPrompt.test.ts +146 -0
- package/apps/server/src/backend/opencode/systemPrompt.ts +284 -0
- package/apps/server/src/backend/paths.ts +57 -0
- package/apps/server/src/backend/prompts/service.ts +100 -0
- package/apps/server/src/backend/queue/queue.test.ts +189 -0
- package/apps/server/src/backend/queue/service.ts +177 -0
- package/apps/server/src/backend/queue/types.ts +39 -0
- package/apps/server/src/backend/run/service.ts +576 -0
- package/apps/server/src/backend/run/storage.ts +47 -0
- package/apps/server/src/backend/run/types.ts +44 -0
- package/apps/server/src/backend/runtime/errors.ts +61 -0
- package/apps/server/src/backend/runtime/index.ts +72 -0
- package/apps/server/src/backend/runtime/memoryPromptDedup.test.ts +153 -0
- package/apps/server/src/backend/runtime/memoryPromptDedup.ts +76 -0
- package/apps/server/src/backend/runtime/opencodeRuntime/backgroundMethods.ts +765 -0
- package/apps/server/src/backend/runtime/opencodeRuntime/coreMethods.ts +705 -0
- package/apps/server/src/backend/runtime/opencodeRuntime/eventMethods.ts +503 -0
- package/apps/server/src/backend/runtime/opencodeRuntime/memoryMethods.ts +462 -0
- package/apps/server/src/backend/runtime/opencodeRuntime/promptMethods.ts +1167 -0
- package/apps/server/src/backend/runtime/opencodeRuntime/shared.ts +254 -0
- package/apps/server/src/backend/runtime/opencodeRuntime.test.ts +2899 -0
- package/apps/server/src/backend/runtime/opencodeRuntime.ts +135 -0
- package/apps/server/src/backend/runtime/sessionScope.ts +45 -0
- package/apps/server/src/backend/skills/service.ts +442 -0
- package/apps/server/src/backend/workspace/resolve.ts +27 -0
- package/apps/server/src/cli/agent-mockingbird.mjs +2522 -0
- package/apps/server/src/cli/agent-mockingbird.test.ts +68 -0
- package/apps/server/src/cli/runtime-assets.mjs +269 -0
- package/apps/server/src/cli/runtime-assets.test.ts +52 -0
- package/apps/server/src/cli/runtime-layout.mjs +75 -0
- package/apps/server/src/cli/standaloneBuild.test.ts +19 -0
- package/apps/server/src/cli/standaloneBuild.ts +19 -0
- package/apps/server/src/cli/standaloneCronBinary.test.ts +187 -0
- package/apps/server/src/index.ts +178 -0
- package/apps/server/tsconfig.json +12 -0
- package/backlog.md +5 -0
- package/bin/agent-mockingbird +2522 -0
- package/bin/runtime-layout.mjs +75 -0
- package/build-bin.ts +34 -0
- package/build-cli.mjs +37 -0
- package/build.ts +40 -0
- package/bun-env.d.ts +11 -0
- package/bun.lock +888 -0
- package/bunfig.toml +2 -0
- package/components.json +21 -0
- package/config.json +130 -0
- package/deploy/RELEASE_INSTALL.md +112 -0
- package/deploy/docker-compose.yml +42 -0
- package/deploy/systemd/README.md +46 -0
- package/deploy/systemd/agent-mockingbird.service +28 -0
- package/deploy/systemd/opencode.service +25 -0
- package/docs/legacy-config-ui-reference.md +51 -0
- package/docs/memory-e2e-trace-2026-03-04.md +63 -0
- package/docs/memory-ops.md +96 -0
- package/docs/memory-runtime-contract.md +42 -0
- package/docs/memory-tuning-remote-2026-03-04.md +59 -0
- package/docs/opencode-rebase-workflow-plan.md +614 -0
- package/docs/opencode-startup-sync-plan.md +94 -0
- package/docs/vendor-opencode.md +41 -0
- package/drizzle/0000_famous_turbo.sql +49 -0
- package/drizzle/0001_cron_memory_aux.sql +160 -0
- package/drizzle/0002_runtime_session_bindings.sql +28 -0
- package/drizzle/0003_background_runs.sql +27 -0
- package/drizzle/0004_memory_open_write.sql +63 -0
- package/drizzle/0005_signal_channel.sql +47 -0
- package/drizzle/0006_usage_event_dimensions.sql +7 -0
- package/drizzle/meta/0000_snapshot.json +341 -0
- package/drizzle/meta/_journal.json +55 -0
- package/drizzle.config.ts +14 -0
- package/eslint.config.mjs +77 -0
- package/knip.json +18 -0
- package/memory/2026-03-04.md +4 -0
- package/opencode.lock.json +16 -0
- package/package.json +67 -0
- package/packages/agent-mockingbird-installer/README.md +31 -0
- package/packages/agent-mockingbird-installer/bin/agent-mockingbird-installer.mjs +44 -0
- package/packages/agent-mockingbird-installer/opencode.lock.json +16 -0
- package/packages/agent-mockingbird-installer/package.json +23 -0
- package/packages/contracts/package.json +19 -0
- package/packages/contracts/src/agentTypes.ts +122 -0
- package/packages/contracts/src/cron.ts +146 -0
- package/packages/contracts/src/dashboard.ts +378 -0
- package/packages/contracts/src/index.ts +3 -0
- package/packages/contracts/tsconfig.json +4 -0
- package/patches/opencode/0001-Wafflebot-OpenCode-baseline.patch +2341 -0
- package/patches/opencode/0002-Fix-OpenCode-web-entry-and-settings-icons.patch +104 -0
- package/patches/opencode/0003-fix-app-remove-duplicate-sidebar-mount.patch +32 -0
- package/patches/opencode/0004-Add-heartbeat-settings-and-usage-nav.patch +506 -0
- package/patches/opencode/0005-Use-chart-icon-for-usage-nav.patch +38 -0
- package/patches/opencode/0006-Modernize-cron-settings.patch +399 -0
- package/patches/opencode/0007-Rename-waffle-namespaces-to-mockingbird.patch +1110 -0
- package/patches/opencode/0008-Remove-cron-contract-section.patch +178 -0
- package/patches/opencode/0009-Rework-cron-tab-as-operations-console.patch +414 -0
- package/patches/opencode/0010-Refine-heartbeat-settings-controls.patch +208 -0
- package/runtime-assets/opencode-config/opencode.jsonc +25 -0
- package/runtime-assets/opencode-config/package.json +5 -0
- package/runtime-assets/opencode-config/plugins/agent-mockingbird.ts +715 -0
- package/runtime-assets/workspace/.agents/skills/config-auditor/SKILL.md +25 -0
- package/runtime-assets/workspace/.agents/skills/config-editor/SKILL.md +24 -0
- package/runtime-assets/workspace/.agents/skills/cron-manager/SKILL.md +57 -0
- package/runtime-assets/workspace/.agents/skills/memory-ops/SKILL.md +120 -0
- package/runtime-assets/workspace/.agents/skills/runtime-diagnose/SKILL.md +25 -0
- package/runtime-assets/workspace/AGENTS.md +56 -0
- package/runtime-assets/workspace/MEMORY.md +4 -0
- package/scripts/build-release-bundle.sh +66 -0
- package/scripts/check-ship.ts +383 -0
- package/scripts/dev-opencode.sh +17 -0
- package/scripts/dev-stack-opencode.sh +15 -0
- package/scripts/dev-stack.sh +61 -0
- package/scripts/install-systemd.sh +87 -0
- package/scripts/memory-e2e.sh +76 -0
- package/scripts/memory-trace-e2e.sh +141 -0
- package/scripts/migrate-opencode-env.ts +108 -0
- package/scripts/onboard/bootstrap.sh +32 -0
- package/scripts/opencode-swap.ts +78 -0
- package/scripts/opencode-sync.ts +715 -0
- package/scripts/runtime-assets-sync.mjs +83 -0
- package/scripts/setup-git-hooks.ts +39 -0
- package/tsconfig.json +45 -0
- package/tui.json +98 -0
- package/turbo.json +36 -0
- package/vendor/OPENCODE_VENDOR.md +13 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { migrateOpenclawWorkspace } from "../../agents/openclawImport";
|
|
4
|
+
import type { RuntimeEngine } from "../../contracts/runtime";
|
|
5
|
+
import type { CronService } from "../../cron/service";
|
|
6
|
+
import type { HeartbeatRuntimeService } from "../../heartbeat/runtimeService";
|
|
7
|
+
import { syncMemoryIndex } from "../../memory/service";
|
|
8
|
+
import type { RunService } from "../../run/service";
|
|
9
|
+
import type { RouteTable } from "../router";
|
|
10
|
+
import type { RuntimeEventStream } from "../sse";
|
|
11
|
+
import { createAgentRoutes } from "./agentRoutes";
|
|
12
|
+
import { createBackgroundRoutes } from "./backgroundRoutes";
|
|
13
|
+
import { createChatRoutes } from "./chatRoutes";
|
|
14
|
+
import { createConfigRoutes } from "./configRoutes";
|
|
15
|
+
import { createCronRoutes } from "./cronRoutes";
|
|
16
|
+
import { createDashboardRoutes } from "./dashboardRoutes";
|
|
17
|
+
import { createEventRoutes } from "./eventRoutes";
|
|
18
|
+
import { createHeartbeatRoutes } from "./heartbeatRoutes";
|
|
19
|
+
import { createMcpRoutes } from "./mcpRoutes";
|
|
20
|
+
import { createMemoryRoutes } from "./memoryRoutes";
|
|
21
|
+
import { createRunRoutes } from "./runRoutes";
|
|
22
|
+
import { createRuntimeRoutes } from "./runtimeRoutes";
|
|
23
|
+
import { createSkillRoutes } from "./skillRoutes";
|
|
24
|
+
import { createUiRoutes } from "./uiRoutes";
|
|
25
|
+
import { createUsageRoutes } from "./usageRoutes";
|
|
26
|
+
|
|
27
|
+
async function importOpenclaw(req: Request) {
|
|
28
|
+
const schema = z.object({
|
|
29
|
+
source: z.discriminatedUnion("mode", [
|
|
30
|
+
z.object({
|
|
31
|
+
mode: z.literal("local"),
|
|
32
|
+
path: z.string().min(1),
|
|
33
|
+
}),
|
|
34
|
+
z.object({
|
|
35
|
+
mode: z.literal("git"),
|
|
36
|
+
url: z.string().min(1),
|
|
37
|
+
ref: z.string().optional(),
|
|
38
|
+
}),
|
|
39
|
+
]),
|
|
40
|
+
targetDirectory: z.string().optional(),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const parsed = schema.safeParse(await req.json());
|
|
44
|
+
if (!parsed.success) {
|
|
45
|
+
return Response.json({ error: "Invalid import request", issues: parsed.error.issues }, { status: 400 });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const migration = await migrateOpenclawWorkspace(parsed.data);
|
|
50
|
+
let memorySync: { attempted: boolean; completed: boolean; error?: string | null } = {
|
|
51
|
+
attempted: false,
|
|
52
|
+
completed: false,
|
|
53
|
+
error: null,
|
|
54
|
+
};
|
|
55
|
+
try {
|
|
56
|
+
await syncMemoryIndex();
|
|
57
|
+
memorySync = { attempted: true, completed: true, error: null };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
memorySync = {
|
|
60
|
+
attempted: true,
|
|
61
|
+
completed: false,
|
|
62
|
+
error: error instanceof Error ? error.message : String(error),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return Response.json({ migration, memorySync });
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return Response.json(
|
|
68
|
+
{ error: error instanceof Error ? error.message : "Failed to import OpenClaw workspace files" },
|
|
69
|
+
{ status: 422 },
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function createApiRoutes(input: {
|
|
75
|
+
runtime: RuntimeEngine;
|
|
76
|
+
cronService: CronService;
|
|
77
|
+
heartbeatService: HeartbeatRuntimeService;
|
|
78
|
+
eventStream: RuntimeEventStream;
|
|
79
|
+
runService: RunService;
|
|
80
|
+
}): RouteTable {
|
|
81
|
+
return {
|
|
82
|
+
"/api/mockingbird/runtime/import-openclaw": {
|
|
83
|
+
POST: (req: Request) => importOpenclaw(req),
|
|
84
|
+
},
|
|
85
|
+
...createRuntimeRoutes({ cronService: input.cronService }),
|
|
86
|
+
...createHeartbeatRoutes(input.heartbeatService),
|
|
87
|
+
...createChatRoutes(input.runtime),
|
|
88
|
+
...createRunRoutes(input.runService),
|
|
89
|
+
...createBackgroundRoutes(input.runtime),
|
|
90
|
+
...createDashboardRoutes(input.runtime),
|
|
91
|
+
...createConfigRoutes(input.eventStream),
|
|
92
|
+
...createUiRoutes(input.runtime),
|
|
93
|
+
...createUsageRoutes(),
|
|
94
|
+
...createEventRoutes(input.eventStream),
|
|
95
|
+
...createAgentRoutes(),
|
|
96
|
+
...createMcpRoutes(),
|
|
97
|
+
...createSkillRoutes(),
|
|
98
|
+
...createCronRoutes(input.cronService),
|
|
99
|
+
...createMemoryRoutes(),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import type { Config as OpencodeConfig } from "@opencode-ai/sdk/client";
|
|
2
|
+
|
|
3
|
+
import { configuredMcpServerSchema } from "../../config/schema";
|
|
4
|
+
import { getConfigSnapshot } from "../../config/service";
|
|
5
|
+
import {
|
|
6
|
+
createOpencodeClientFromConnection,
|
|
7
|
+
createOpencodeV2ClientFromConnection,
|
|
8
|
+
unwrapSdkData,
|
|
9
|
+
} from "../../opencode/client";
|
|
10
|
+
|
|
11
|
+
function getConnectionConfig() {
|
|
12
|
+
const snapshot = getConfigSnapshot();
|
|
13
|
+
return {
|
|
14
|
+
baseUrl: snapshot.config.runtime.opencode.baseUrl,
|
|
15
|
+
directory: snapshot.config.workspace.pinnedDirectory,
|
|
16
|
+
timeoutMs: snapshot.config.runtime.opencode.timeoutMs,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
21
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function loadOpencodeConfig() {
|
|
25
|
+
const connection = getConnectionConfig();
|
|
26
|
+
const client = createOpencodeClientFromConnection(connection);
|
|
27
|
+
return unwrapSdkData<OpencodeConfig>(
|
|
28
|
+
await client.config.get({
|
|
29
|
+
responseStyle: "data",
|
|
30
|
+
throwOnError: true,
|
|
31
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function persistMcpServers(servers: Array<ReturnType<typeof configuredMcpServerSchema.parse>>) {
|
|
37
|
+
const connection = getConnectionConfig();
|
|
38
|
+
const client = createOpencodeClientFromConnection(connection);
|
|
39
|
+
const current = await loadOpencodeConfig();
|
|
40
|
+
const nextMcp = Object.fromEntries(
|
|
41
|
+
servers.map(server => [
|
|
42
|
+
server.id,
|
|
43
|
+
server.type === "remote"
|
|
44
|
+
? {
|
|
45
|
+
type: "remote",
|
|
46
|
+
url: server.url,
|
|
47
|
+
enabled: server.enabled,
|
|
48
|
+
headers: server.headers,
|
|
49
|
+
...(server.oauth === "off" ? { oauth: false } : {}),
|
|
50
|
+
...(typeof server.timeoutMs === "number" ? { timeout: server.timeoutMs } : {}),
|
|
51
|
+
}
|
|
52
|
+
: {
|
|
53
|
+
type: "local",
|
|
54
|
+
command: server.command,
|
|
55
|
+
enabled: server.enabled,
|
|
56
|
+
environment: server.environment,
|
|
57
|
+
...(typeof server.timeoutMs === "number" ? { timeout: server.timeoutMs } : {}),
|
|
58
|
+
},
|
|
59
|
+
]),
|
|
60
|
+
);
|
|
61
|
+
const nextConfig = {
|
|
62
|
+
...(current as Record<string, unknown>),
|
|
63
|
+
mcp: nextMcp,
|
|
64
|
+
} as OpencodeConfig;
|
|
65
|
+
|
|
66
|
+
await client.config.update({
|
|
67
|
+
body: nextConfig,
|
|
68
|
+
responseStyle: "data",
|
|
69
|
+
throwOnError: true,
|
|
70
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
71
|
+
});
|
|
72
|
+
await client.instance.dispose({
|
|
73
|
+
responseStyle: "data",
|
|
74
|
+
throwOnError: false,
|
|
75
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
76
|
+
}).catch(() => undefined);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeServers(config: OpencodeConfig) {
|
|
80
|
+
const raw = (config as Record<string, unknown>).mcp;
|
|
81
|
+
if (!isPlainObject(raw)) return [];
|
|
82
|
+
const servers = [];
|
|
83
|
+
for (const [id, value] of Object.entries(raw)) {
|
|
84
|
+
if (!isPlainObject(value) || typeof value.type !== "string") continue;
|
|
85
|
+
const candidate = configuredMcpServerSchema.safeParse({ id, ...value });
|
|
86
|
+
if (candidate.success) {
|
|
87
|
+
servers.push(candidate.data);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return servers.sort((left, right) => left.id.localeCompare(right.id));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function loadStatuses() {
|
|
94
|
+
const connection = getConnectionConfig();
|
|
95
|
+
const client = createOpencodeV2ClientFromConnection(connection);
|
|
96
|
+
return unwrapSdkData<Record<string, unknown>>(
|
|
97
|
+
await client.mcp.status(undefined, {
|
|
98
|
+
responseStyle: "data",
|
|
99
|
+
throwOnError: true,
|
|
100
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function createMcpRoutes() {
|
|
106
|
+
return {
|
|
107
|
+
"/api/mockingbird/mcp": {
|
|
108
|
+
GET: async () => {
|
|
109
|
+
try {
|
|
110
|
+
const config = await loadOpencodeConfig();
|
|
111
|
+
const servers = normalizeServers(config);
|
|
112
|
+
const status = await loadStatuses().catch(() => ({}));
|
|
113
|
+
return Response.json({ servers, status });
|
|
114
|
+
} catch (error) {
|
|
115
|
+
const message = error instanceof Error ? error.message : "Failed to load MCP config";
|
|
116
|
+
return Response.json({ error: message }, { status: 502 });
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
PUT: async (req: Request) => {
|
|
120
|
+
const body = (await req.json()) as { servers?: unknown };
|
|
121
|
+
if (!Array.isArray(body.servers)) {
|
|
122
|
+
return Response.json({ error: "servers must be an array" }, { status: 400 });
|
|
123
|
+
}
|
|
124
|
+
const parsedServers = [];
|
|
125
|
+
for (const server of body.servers) {
|
|
126
|
+
const parsed = configuredMcpServerSchema.safeParse(server);
|
|
127
|
+
if (!parsed.success) {
|
|
128
|
+
return Response.json(
|
|
129
|
+
{ error: parsed.error.issues[0]?.message ?? "Invalid MCP server definition" },
|
|
130
|
+
{ status: 400 },
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
parsedServers.push(parsed.data);
|
|
134
|
+
}
|
|
135
|
+
await persistMcpServers(parsedServers);
|
|
136
|
+
const config = await loadOpencodeConfig();
|
|
137
|
+
return Response.json({ servers: normalizeServers(config), status: await loadStatuses().catch(() => ({})) });
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
"/api/mockingbird/mcp/:id/connect": {
|
|
142
|
+
POST: async (req: Request & { params: { id: string } }) => {
|
|
143
|
+
const connection = getConnectionConfig();
|
|
144
|
+
const client = createOpencodeV2ClientFromConnection(connection);
|
|
145
|
+
const connected = unwrapSdkData<boolean>(
|
|
146
|
+
await client.mcp.connect(
|
|
147
|
+
{ name: req.params.id },
|
|
148
|
+
{
|
|
149
|
+
responseStyle: "data",
|
|
150
|
+
throwOnError: true,
|
|
151
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
152
|
+
},
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
return Response.json({ connected, status: await loadStatuses() });
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
"/api/mockingbird/mcp/:id/disconnect": {
|
|
160
|
+
POST: async (req: Request & { params: { id: string } }) => {
|
|
161
|
+
const connection = getConnectionConfig();
|
|
162
|
+
const client = createOpencodeV2ClientFromConnection(connection);
|
|
163
|
+
const disconnected = unwrapSdkData<boolean>(
|
|
164
|
+
await client.mcp.disconnect(
|
|
165
|
+
{ name: req.params.id },
|
|
166
|
+
{
|
|
167
|
+
responseStyle: "data",
|
|
168
|
+
throwOnError: true,
|
|
169
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
170
|
+
},
|
|
171
|
+
),
|
|
172
|
+
);
|
|
173
|
+
return Response.json({ disconnected, status: await loadStatuses() });
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
"/api/mockingbird/mcp/:id/auth/start": {
|
|
178
|
+
POST: async (req: Request & { params: { id: string } }) => {
|
|
179
|
+
const connection = getConnectionConfig();
|
|
180
|
+
const client = createOpencodeV2ClientFromConnection(connection);
|
|
181
|
+
const authorization = unwrapSdkData<{ authorizationUrl: string }>(
|
|
182
|
+
await client.mcp.auth.start(
|
|
183
|
+
{ name: req.params.id },
|
|
184
|
+
{
|
|
185
|
+
responseStyle: "data",
|
|
186
|
+
throwOnError: true,
|
|
187
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
188
|
+
},
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
return Response.json(authorization);
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
"/api/mockingbird/mcp/:id/auth/remove": {
|
|
196
|
+
POST: async (req: Request & { params: { id: string } }) => {
|
|
197
|
+
const connection = getConnectionConfig();
|
|
198
|
+
const client = createOpencodeV2ClientFromConnection(connection);
|
|
199
|
+
const result = unwrapSdkData<{ success: true }>(
|
|
200
|
+
await client.mcp.auth.remove(
|
|
201
|
+
{ name: req.params.id },
|
|
202
|
+
{
|
|
203
|
+
responseStyle: "data",
|
|
204
|
+
throwOnError: true,
|
|
205
|
+
signal: AbortSignal.timeout(connection.timeoutMs),
|
|
206
|
+
},
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
return Response.json(result);
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMemoryStatus,
|
|
3
|
+
listMemoryWriteEvents,
|
|
4
|
+
readMemoryFileSlice,
|
|
5
|
+
rememberMemory,
|
|
6
|
+
searchMemoryDetailed,
|
|
7
|
+
searchMemory,
|
|
8
|
+
syncMemoryIndex,
|
|
9
|
+
validateMemoryRememberInput,
|
|
10
|
+
} from "../../memory/service";
|
|
11
|
+
import { parseMemoryRememberBody } from "../parsers";
|
|
12
|
+
|
|
13
|
+
export function createMemoryRoutes() {
|
|
14
|
+
return {
|
|
15
|
+
"/api/mockingbird/memory/status": {
|
|
16
|
+
GET: async () => {
|
|
17
|
+
try {
|
|
18
|
+
return Response.json({ status: await getMemoryStatus() });
|
|
19
|
+
} catch (error) {
|
|
20
|
+
const message = error instanceof Error ? error.message : "Failed to load memory status";
|
|
21
|
+
return Response.json({ error: message }, { status: 500 });
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
"/api/mockingbird/memory/activity": {
|
|
27
|
+
GET: async (req: Request) => {
|
|
28
|
+
try {
|
|
29
|
+
const url = new URL(req.url);
|
|
30
|
+
const requestedLimit = Number(url.searchParams.get("limit") ?? "20");
|
|
31
|
+
const events = await listMemoryWriteEvents(requestedLimit);
|
|
32
|
+
return Response.json({ events });
|
|
33
|
+
} catch (error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : "Failed to load memory activity";
|
|
35
|
+
return Response.json({ error: message }, { status: 500 });
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
"/api/mockingbird/memory/sync": {
|
|
41
|
+
POST: async () => {
|
|
42
|
+
try {
|
|
43
|
+
await syncMemoryIndex();
|
|
44
|
+
return Response.json({ status: await getMemoryStatus() });
|
|
45
|
+
} catch (error) {
|
|
46
|
+
const message = error instanceof Error ? error.message : "Memory sync failed";
|
|
47
|
+
return Response.json({ error: message }, { status: 502 });
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
"/api/mockingbird/memory/reindex": {
|
|
53
|
+
POST: async () => {
|
|
54
|
+
try {
|
|
55
|
+
await syncMemoryIndex({ force: true });
|
|
56
|
+
return Response.json({ status: await getMemoryStatus() });
|
|
57
|
+
} catch (error) {
|
|
58
|
+
const message = error instanceof Error ? error.message : "Memory reindex failed";
|
|
59
|
+
return Response.json({ error: message }, { status: 502 });
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
"/api/mockingbird/memory/retrieve": {
|
|
65
|
+
POST: async (req: Request) => {
|
|
66
|
+
const body = (await req.json()) as { query?: string; maxResults?: number; minScore?: number; debug?: boolean };
|
|
67
|
+
const query = body.query?.trim();
|
|
68
|
+
if (!query) {
|
|
69
|
+
return Response.json({ error: "query is required" }, { status: 400 });
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const options = {
|
|
73
|
+
maxResults: typeof body.maxResults === "number" ? body.maxResults : undefined,
|
|
74
|
+
minScore: typeof body.minScore === "number" ? body.minScore : undefined,
|
|
75
|
+
};
|
|
76
|
+
if (body.debug) {
|
|
77
|
+
const detailed = await searchMemoryDetailed(query, options);
|
|
78
|
+
return Response.json({ results: detailed.results, debug: detailed.debug });
|
|
79
|
+
}
|
|
80
|
+
const results = await searchMemory(query, options);
|
|
81
|
+
return Response.json({ results, debug: undefined });
|
|
82
|
+
} catch (error) {
|
|
83
|
+
const message = error instanceof Error ? error.message : "Memory retrieve failed";
|
|
84
|
+
return Response.json({ error: message }, { status: 502 });
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
"/api/mockingbird/memory/read": {
|
|
90
|
+
POST: async (req: Request) => {
|
|
91
|
+
const body = (await req.json()) as { path?: string; from?: number; lines?: number };
|
|
92
|
+
const relPath = body.path?.trim();
|
|
93
|
+
if (!relPath) {
|
|
94
|
+
return Response.json({ error: "path is required" }, { status: 400 });
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const result = await readMemoryFileSlice({
|
|
98
|
+
relPath,
|
|
99
|
+
from: typeof body.from === "number" ? body.from : undefined,
|
|
100
|
+
lines: typeof body.lines === "number" ? body.lines : undefined,
|
|
101
|
+
});
|
|
102
|
+
return Response.json(result);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const message = error instanceof Error ? error.message : "Memory read failed";
|
|
105
|
+
return Response.json({ error: message }, { status: 400 });
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
"/api/mockingbird/memory/remember": {
|
|
111
|
+
POST: async (req: Request) => {
|
|
112
|
+
const body = parseMemoryRememberBody(await req.json());
|
|
113
|
+
if (!body) {
|
|
114
|
+
return Response.json(
|
|
115
|
+
{
|
|
116
|
+
error:
|
|
117
|
+
"Invalid payload. Expected { source?, content, entities?, confidence?, supersedes?, sessionId?, topic?, ttl? }",
|
|
118
|
+
},
|
|
119
|
+
{ status: 400 },
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const result = await rememberMemory(body);
|
|
124
|
+
return Response.json(result, { status: result.accepted ? 201 : 422 });
|
|
125
|
+
} catch (error) {
|
|
126
|
+
const message = error instanceof Error ? error.message : "Memory write failed";
|
|
127
|
+
return Response.json({ error: message }, { status: 502 });
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
"/api/mockingbird/memory/remember/validate": {
|
|
133
|
+
POST: async (req: Request) => {
|
|
134
|
+
const body = parseMemoryRememberBody(await req.json());
|
|
135
|
+
if (!body) {
|
|
136
|
+
return Response.json(
|
|
137
|
+
{
|
|
138
|
+
error:
|
|
139
|
+
"Invalid payload. Expected { source?, content, entities?, confidence?, supersedes?, sessionId?, topic?, ttl? }",
|
|
140
|
+
},
|
|
141
|
+
{ status: 400 },
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const validation = await validateMemoryRememberInput(body);
|
|
146
|
+
return Response.json({ validation });
|
|
147
|
+
} catch (error) {
|
|
148
|
+
const message = error instanceof Error ? error.message : "Memory validation failed";
|
|
149
|
+
return Response.json({ error: message }, { status: 502 });
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|