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,1110 @@
|
|
|
1
|
+
From aa99a5bc6827bc92d46194cf9b1fd0b8c05f3181 Mon Sep 17 00:00:00 2001
|
|
2
|
+
From: Matt Campbell <matt@battleshopper.com>
|
|
3
|
+
Date: Thu, 19 Mar 2026 15:30:30 -0500
|
|
4
|
+
Subject: [PATCH 07/10] Rename waffle namespaces to mockingbird
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
.../app/src/components/settings-agents.tsx | 38 +++---
|
|
8
|
+
.../src/components/settings-cron-data.test.ts | 12 +-
|
|
9
|
+
.../app/src/components/settings-cron-data.ts | 12 +-
|
|
10
|
+
packages/app/src/components/settings-cron.tsx | 52 ++++-----
|
|
11
|
+
.../app/src/components/settings-heartbeat.tsx | 108 +++++++++---------
|
|
12
|
+
packages/app/src/components/settings-mcp.tsx | 36 +++---
|
|
13
|
+
...ed.tsx => settings-mockingbird-shared.tsx} | 16 +--
|
|
14
|
+
.../app/src/components/settings-runtime.tsx | 38 +++---
|
|
15
|
+
.../app/src/components/settings-skills.tsx | 50 ++++----
|
|
16
|
+
packages/app/src/i18n/en.ts | 2 +-
|
|
17
|
+
packages/app/src/pages/directory-layout.tsx | 2 +-
|
|
18
|
+
packages/app/src/pages/home.tsx | 2 +-
|
|
19
|
+
packages/app/src/pages/layout.tsx | 2 +-
|
|
20
|
+
.../src/utils/{waffle.ts => mockingbird.ts} | 12 +-
|
|
21
|
+
14 files changed, 191 insertions(+), 191 deletions(-)
|
|
22
|
+
rename packages/app/src/components/{settings-waffle-shared.tsx => settings-mockingbird-shared.tsx} (85%)
|
|
23
|
+
rename packages/app/src/utils/{waffle.ts => mockingbird.ts} (75%)
|
|
24
|
+
|
|
25
|
+
diff --git a/packages/app/src/components/settings-agents.tsx b/packages/app/src/components/settings-agents.tsx
|
|
26
|
+
index dda48a075..81b547fb4 100644
|
|
27
|
+
--- a/packages/app/src/components/settings-agents.tsx
|
|
28
|
+
+++ b/packages/app/src/components/settings-agents.tsx
|
|
29
|
+
@@ -2,8 +2,8 @@ import { Button } from "@opencode-ai/ui/button"
|
|
30
|
+
import { showToast } from "@opencode-ai/ui/toast"
|
|
31
|
+
import { onMount, Show, type Component } from "solid-js"
|
|
32
|
+
import { createStore } from "solid-js/store"
|
|
33
|
+
-import { prettyJson, waffleJson } from "@/utils/waffle"
|
|
34
|
+
-import { WaffleCard, WaffleMetaRow, WaffleNotice, WaffleSettingsPage, WaffleSettingsSection, WaffleTextArea, WaffleToolbar } from "./settings-waffle-shared"
|
|
35
|
+
+import { prettyJson, mockingbirdJson } from "@/utils/mockingbird"
|
|
36
|
+
+import { MockingbirdCard, MockingbirdMetaRow, MockingbirdNotice, MockingbirdSettingsPage, MockingbirdSettingsSection, MockingbirdTextArea, MockingbirdToolbar } from "./settings-mockingbird-shared"
|
|
37
|
+
|
|
38
|
+
type AgentType = {
|
|
39
|
+
id: string
|
|
40
|
+
@@ -45,7 +45,7 @@ export const SettingsAgents: Component = () => {
|
|
41
|
+
setState("loading", true)
|
|
42
|
+
setState("error", "")
|
|
43
|
+
try {
|
|
44
|
+
- const payload = await waffleJson<AgentsPayload>("/api/waffle/agents")
|
|
45
|
+
+ const payload = await mockingbirdJson<AgentsPayload>("/api/mockingbird/agents")
|
|
46
|
+
setState("payload", payload)
|
|
47
|
+
setState("text", prettyJson(payload.agentTypes))
|
|
48
|
+
} catch (error) {
|
|
49
|
+
@@ -77,7 +77,7 @@ export const SettingsAgents: Component = () => {
|
|
50
|
+
setState("saving", true)
|
|
51
|
+
setState("error", "")
|
|
52
|
+
try {
|
|
53
|
+
- const payload = await waffleJson<AgentsPayload>("/api/waffle/agents", {
|
|
54
|
+
+ const payload = await mockingbirdJson<AgentsPayload>("/api/mockingbird/agents", {
|
|
55
|
+
method: "PATCH",
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
upserts: parsed,
|
|
58
|
+
@@ -104,44 +104,44 @@ export const SettingsAgents: Component = () => {
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
- <WaffleSettingsPage
|
|
63
|
+
+ <MockingbirdSettingsPage
|
|
64
|
+
title="Agents"
|
|
65
|
+
description="Manage OpenCode agent definitions stored in the pinned workspace's .opencode/opencode.jsonc."
|
|
66
|
+
actions={
|
|
67
|
+
- <WaffleToolbar>
|
|
68
|
+
+ <MockingbirdToolbar>
|
|
69
|
+
<Button variant="ghost" size="large" onClick={() => void load()} disabled={state.loading || state.saving}>
|
|
70
|
+
Refresh
|
|
71
|
+
</Button>
|
|
72
|
+
<Button size="large" onClick={() => void save()} disabled={state.loading || state.saving}>
|
|
73
|
+
Save
|
|
74
|
+
</Button>
|
|
75
|
+
- </WaffleToolbar>
|
|
76
|
+
+ </MockingbirdToolbar>
|
|
77
|
+
}
|
|
78
|
+
>
|
|
79
|
+
<Show when={state.error}>
|
|
80
|
+
- <WaffleNotice tone="error">{state.error}</WaffleNotice>
|
|
81
|
+
+ <MockingbirdNotice tone="error">{state.error}</MockingbirdNotice>
|
|
82
|
+
</Show>
|
|
83
|
+
|
|
84
|
+
<Show when={state.payload?.storage}>
|
|
85
|
+
{(storage) => (
|
|
86
|
+
- <WaffleSettingsSection title="Storage">
|
|
87
|
+
- <WaffleMetaRow label="Workspace directory" value={storage().directory} />
|
|
88
|
+
- <WaffleMetaRow label="Config file" value={storage().configFilePath} />
|
|
89
|
+
- <WaffleMetaRow label="Persistence mode" value={storage().persistenceMode} />
|
|
90
|
+
- </WaffleSettingsSection>
|
|
91
|
+
+ <MockingbirdSettingsSection title="Storage">
|
|
92
|
+
+ <MockingbirdMetaRow label="Workspace directory" value={storage().directory} />
|
|
93
|
+
+ <MockingbirdMetaRow label="Config file" value={storage().configFilePath} />
|
|
94
|
+
+ <MockingbirdMetaRow label="Persistence mode" value={storage().persistenceMode} />
|
|
95
|
+
+ </MockingbirdSettingsSection>
|
|
96
|
+
)}
|
|
97
|
+
</Show>
|
|
98
|
+
|
|
99
|
+
- <WaffleSettingsSection title="Agent editor" description="Edit the current agent type array as JSON.">
|
|
100
|
+
- <WaffleCard>
|
|
101
|
+
- <WaffleTextArea
|
|
102
|
+
+ <MockingbirdSettingsSection title="Agent editor" description="Edit the current agent type array as JSON.">
|
|
103
|
+
+ <MockingbirdCard>
|
|
104
|
+
+ <MockingbirdTextArea
|
|
105
|
+
rows={22}
|
|
106
|
+
value={state.text}
|
|
107
|
+
onInput={(event) => setState("text", event.currentTarget.value)}
|
|
108
|
+
spellcheck={false}
|
|
109
|
+
/>
|
|
110
|
+
- </WaffleCard>
|
|
111
|
+
- </WaffleSettingsSection>
|
|
112
|
+
- </WaffleSettingsPage>
|
|
113
|
+
+ </MockingbirdCard>
|
|
114
|
+
+ </MockingbirdSettingsSection>
|
|
115
|
+
+ </MockingbirdSettingsPage>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
diff --git a/packages/app/src/components/settings-cron-data.test.ts b/packages/app/src/components/settings-cron-data.test.ts
|
|
119
|
+
index faf702691..c1ec8fcd3 100644
|
|
120
|
+
--- a/packages/app/src/components/settings-cron-data.test.ts
|
|
121
|
+
+++ b/packages/app/src/components/settings-cron-data.test.ts
|
|
122
|
+
@@ -6,13 +6,13 @@ describe("loadCronSettings", () => {
|
|
123
|
+
const calls: Array<{ path: string; init?: RequestInit }> = []
|
|
124
|
+
const requestJson = async <T>(path: string, init?: RequestInit) => {
|
|
125
|
+
calls.push({ path, init })
|
|
126
|
+
- if (path === "/api/waffle/cron/jobs") {
|
|
127
|
+
+ if (path === "/api/mockingbird/cron/jobs") {
|
|
128
|
+
return { jobs: [] } as T
|
|
129
|
+
}
|
|
130
|
+
- if (path === "/api/waffle/cron/health") {
|
|
131
|
+
+ if (path === "/api/mockingbird/cron/health") {
|
|
132
|
+
return { health: { enabled: true, jobs: { total: 0, enabled: 0 } } } as T
|
|
133
|
+
}
|
|
134
|
+
- if (path === "/api/waffle/cron/manage") {
|
|
135
|
+
+ if (path === "/api/mockingbird/cron/manage") {
|
|
136
|
+
return {
|
|
137
|
+
contract: {
|
|
138
|
+
runModes: {
|
|
139
|
+
@@ -36,10 +36,10 @@ describe("loadCronSettings", () => {
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
expect(calls).toEqual([
|
|
143
|
+
- { path: "/api/waffle/cron/jobs", init: undefined },
|
|
144
|
+
- { path: "/api/waffle/cron/health", init: undefined },
|
|
145
|
+
+ { path: "/api/mockingbird/cron/jobs", init: undefined },
|
|
146
|
+
+ { path: "/api/mockingbird/cron/health", init: undefined },
|
|
147
|
+
{
|
|
148
|
+
- path: "/api/waffle/cron/manage",
|
|
149
|
+
+ path: "/api/mockingbird/cron/manage",
|
|
150
|
+
init: {
|
|
151
|
+
method: "POST",
|
|
152
|
+
body: JSON.stringify({ action: "describe_contract" }),
|
|
153
|
+
diff --git a/packages/app/src/components/settings-cron-data.ts b/packages/app/src/components/settings-cron-data.ts
|
|
154
|
+
index c747ce06f..2eeab5f94 100644
|
|
155
|
+
--- a/packages/app/src/components/settings-cron-data.ts
|
|
156
|
+
+++ b/packages/app/src/components/settings-cron-data.ts
|
|
157
|
+
@@ -1,4 +1,4 @@
|
|
158
|
+
-import { prettyJson, waffleJson } from "@/utils/waffle"
|
|
159
|
+
+import { prettyJson, mockingbirdJson } from "@/utils/mockingbird"
|
|
160
|
+
|
|
161
|
+
export type CronJobDefinition = {
|
|
162
|
+
id: string
|
|
163
|
+
@@ -49,7 +49,7 @@ type CronContractResponse = {
|
|
164
|
+
contract: CronContract
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
-type WaffleJson = <T>(path: string, init?: RequestInit) => Promise<T>
|
|
168
|
+
+type MockingbirdJson = <T>(path: string, init?: RequestInit) => Promise<T>
|
|
169
|
+
|
|
170
|
+
const DEFAULT_AGENT_JOB = {
|
|
171
|
+
name: "Hourly review",
|
|
172
|
+
@@ -63,11 +63,11 @@ const DEFAULT_AGENT_JOB = {
|
|
173
|
+
|
|
174
|
+
export const DEFAULT_JOB = prettyJson(DEFAULT_AGENT_JOB)
|
|
175
|
+
|
|
176
|
+
-export async function loadCronSettings(requestJson: WaffleJson = waffleJson) {
|
|
177
|
+
+export async function loadCronSettings(requestJson: MockingbirdJson = mockingbirdJson) {
|
|
178
|
+
const [jobs, health, contract] = await Promise.all([
|
|
179
|
+
- requestJson<CronJobsResponse>("/api/waffle/cron/jobs"),
|
|
180
|
+
- requestJson<CronHealthResponse>("/api/waffle/cron/health"),
|
|
181
|
+
- requestJson<CronContractResponse>("/api/waffle/cron/manage", {
|
|
182
|
+
+ requestJson<CronJobsResponse>("/api/mockingbird/cron/jobs"),
|
|
183
|
+
+ requestJson<CronHealthResponse>("/api/mockingbird/cron/health"),
|
|
184
|
+
+ requestJson<CronContractResponse>("/api/mockingbird/cron/manage", {
|
|
185
|
+
method: "POST",
|
|
186
|
+
body: JSON.stringify({ action: "describe_contract" }),
|
|
187
|
+
}),
|
|
188
|
+
diff --git a/packages/app/src/components/settings-cron.tsx b/packages/app/src/components/settings-cron.tsx
|
|
189
|
+
index a5b15cb11..67f282245 100644
|
|
190
|
+
--- a/packages/app/src/components/settings-cron.tsx
|
|
191
|
+
+++ b/packages/app/src/components/settings-cron.tsx
|
|
192
|
+
@@ -2,9 +2,9 @@ import { Button } from "@opencode-ai/ui/button"
|
|
193
|
+
import { showToast } from "@opencode-ai/ui/toast"
|
|
194
|
+
import { For, onMount, Show, type Component } from "solid-js"
|
|
195
|
+
import { createStore } from "solid-js/store"
|
|
196
|
+
-import { waffleJson } from "@/utils/waffle"
|
|
197
|
+
+import { mockingbirdJson } from "@/utils/mockingbird"
|
|
198
|
+
import { DEFAULT_JOB, loadCronSettings, serializeCronJobForEdit, type CronContract, type CronHealthSnapshot, type CronJobDefinition } from "./settings-cron-data"
|
|
199
|
+
-import { WaffleCard, WaffleMetaRow, WaffleNotice, WaffleSettingsPage, WaffleSettingsSection, WaffleTextArea, WaffleToolbar } from "./settings-waffle-shared"
|
|
200
|
+
+import { MockingbirdCard, MockingbirdMetaRow, MockingbirdNotice, MockingbirdSettingsPage, MockingbirdSettingsSection, MockingbirdTextArea, MockingbirdToolbar } from "./settings-mockingbird-shared"
|
|
201
|
+
|
|
202
|
+
export const SettingsCron: Component = () => {
|
|
203
|
+
const [state, setState] = createStore({
|
|
204
|
+
@@ -51,7 +51,7 @@ export const SettingsCron: Component = () => {
|
|
205
|
+
setState("saving", true)
|
|
206
|
+
setState("error", "")
|
|
207
|
+
try {
|
|
208
|
+
- await waffleJson("/api/waffle/cron/jobs", {
|
|
209
|
+
+ await mockingbirdJson("/api/mockingbird/cron/jobs", {
|
|
210
|
+
method: "POST",
|
|
211
|
+
body: JSON.stringify(payload),
|
|
212
|
+
})
|
|
213
|
+
@@ -82,7 +82,7 @@ export const SettingsCron: Component = () => {
|
|
214
|
+
setState("busyId", state.editingId)
|
|
215
|
+
setState("error", "")
|
|
216
|
+
try {
|
|
217
|
+
- await waffleJson(`/api/waffle/cron/jobs/${encodeURIComponent(state.editingId)}`, {
|
|
218
|
+
+ await mockingbirdJson(`/api/mockingbird/cron/jobs/${encodeURIComponent(state.editingId)}`, {
|
|
219
|
+
method: "PATCH",
|
|
220
|
+
body: JSON.stringify(payload),
|
|
221
|
+
})
|
|
222
|
+
@@ -99,7 +99,7 @@ export const SettingsCron: Component = () => {
|
|
223
|
+
async function runNow(id: string) {
|
|
224
|
+
setState("busyId", id)
|
|
225
|
+
try {
|
|
226
|
+
- await waffleJson(`/api/waffle/cron/jobs/${encodeURIComponent(id)}/run`, {
|
|
227
|
+
+ await mockingbirdJson(`/api/mockingbird/cron/jobs/${encodeURIComponent(id)}/run`, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
})
|
|
230
|
+
showToast({
|
|
231
|
+
@@ -117,7 +117,7 @@ export const SettingsCron: Component = () => {
|
|
232
|
+
async function remove(id: string) {
|
|
233
|
+
setState("busyId", id)
|
|
234
|
+
try {
|
|
235
|
+
- await waffleJson(`/api/waffle/cron/jobs/${encodeURIComponent(id)}`, {
|
|
236
|
+
+ await mockingbirdJson(`/api/mockingbird/cron/jobs/${encodeURIComponent(id)}`, {
|
|
237
|
+
method: "DELETE",
|
|
238
|
+
})
|
|
239
|
+
await refresh()
|
|
240
|
+
@@ -133,34 +133,34 @@ export const SettingsCron: Component = () => {
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
- <WaffleSettingsPage
|
|
245
|
+
+ <MockingbirdSettingsPage
|
|
246
|
+
title="Cron"
|
|
247
|
+
description="Inspect cron health, create jobs, update jobs with JSON patches, and run them immediately."
|
|
248
|
+
actions={
|
|
249
|
+
- <WaffleToolbar>
|
|
250
|
+
+ <MockingbirdToolbar>
|
|
251
|
+
<Button variant="ghost" size="large" onClick={() => void refresh()} disabled={state.loading || state.saving}>
|
|
252
|
+
Refresh
|
|
253
|
+
</Button>
|
|
254
|
+
- </WaffleToolbar>
|
|
255
|
+
+ </MockingbirdToolbar>
|
|
256
|
+
}
|
|
257
|
+
>
|
|
258
|
+
<Show when={state.error}>
|
|
259
|
+
- <WaffleNotice tone="error">{state.error}</WaffleNotice>
|
|
260
|
+
+ <MockingbirdNotice tone="error">{state.error}</MockingbirdNotice>
|
|
261
|
+
</Show>
|
|
262
|
+
|
|
263
|
+
<Show when={state.health}>
|
|
264
|
+
{(health) => (
|
|
265
|
+
- <WaffleSettingsSection title="Cron health">
|
|
266
|
+
- <WaffleMetaRow label="Enabled" value={health().enabled ? "Yes" : "No"} />
|
|
267
|
+
- <WaffleMetaRow label="Total jobs" value={String(health().jobs.total)} />
|
|
268
|
+
- <WaffleMetaRow label="Enabled jobs" value={String(health().jobs.enabled)} />
|
|
269
|
+
- </WaffleSettingsSection>
|
|
270
|
+
+ <MockingbirdSettingsSection title="Cron health">
|
|
271
|
+
+ <MockingbirdMetaRow label="Enabled" value={health().enabled ? "Yes" : "No"} />
|
|
272
|
+
+ <MockingbirdMetaRow label="Total jobs" value={String(health().jobs.total)} />
|
|
273
|
+
+ <MockingbirdMetaRow label="Enabled jobs" value={String(health().jobs.enabled)} />
|
|
274
|
+
+ </MockingbirdSettingsSection>
|
|
275
|
+
)}
|
|
276
|
+
</Show>
|
|
277
|
+
|
|
278
|
+
<Show when={state.contract}>
|
|
279
|
+
{(contract) => (
|
|
280
|
+
- <WaffleSettingsSection title="Run mode contract" description="Current backend requirements for each cron run mode.">
|
|
281
|
+
+ <MockingbirdSettingsSection title="Run mode contract" description="Current backend requirements for each cron run mode.">
|
|
282
|
+
<For each={Object.entries(contract().runModes)}>
|
|
283
|
+
{([mode, details]) => (
|
|
284
|
+
<div class="px-4 py-4 border-b border-border-weak-base last:border-none flex flex-col gap-1">
|
|
285
|
+
@@ -177,11 +177,11 @@ export const SettingsCron: Component = () => {
|
|
286
|
+
</div>
|
|
287
|
+
)}
|
|
288
|
+
</For>
|
|
289
|
+
- </WaffleSettingsSection>
|
|
290
|
+
+ </MockingbirdSettingsSection>
|
|
291
|
+
)}
|
|
292
|
+
</Show>
|
|
293
|
+
|
|
294
|
+
- <WaffleSettingsSection title="Jobs">
|
|
295
|
+
+ <MockingbirdSettingsSection title="Jobs">
|
|
296
|
+
<Show
|
|
297
|
+
when={state.jobs.length > 0}
|
|
298
|
+
fallback={<div class="px-4 py-4 text-14-regular text-text-weak">No cron jobs configured.</div>}
|
|
299
|
+
@@ -231,7 +231,7 @@ export const SettingsCron: Component = () => {
|
|
300
|
+
|
|
301
|
+
<Show when={state.editingId === job.id}>
|
|
302
|
+
<div class="flex flex-col gap-3">
|
|
303
|
+
- <WaffleTextArea
|
|
304
|
+
+ <MockingbirdTextArea
|
|
305
|
+
rows={12}
|
|
306
|
+
value={state.editText}
|
|
307
|
+
onInput={(event) => setState("editText", event.currentTarget.value)}
|
|
308
|
+
@@ -247,10 +247,10 @@ export const SettingsCron: Component = () => {
|
|
309
|
+
)}
|
|
310
|
+
</For>
|
|
311
|
+
</Show>
|
|
312
|
+
- </WaffleSettingsSection>
|
|
313
|
+
+ </MockingbirdSettingsSection>
|
|
314
|
+
|
|
315
|
+
- <WaffleSettingsSection title="Create job" description="Post a complete cron job definition as JSON using the current run mode contract.">
|
|
316
|
+
- <WaffleCard
|
|
317
|
+
+ <MockingbirdSettingsSection title="Create job" description="Post a complete cron job definition as JSON using the current run mode contract.">
|
|
318
|
+
+ <MockingbirdCard
|
|
319
|
+
footer={
|
|
320
|
+
<div class="flex justify-end">
|
|
321
|
+
<Button size="large" onClick={() => void createJob()} disabled={state.saving}>
|
|
322
|
+
@@ -259,9 +259,9 @@ export const SettingsCron: Component = () => {
|
|
323
|
+
</div>
|
|
324
|
+
}
|
|
325
|
+
>
|
|
326
|
+
- <WaffleTextArea rows={16} value={state.createText} onInput={(event) => setState("createText", event.currentTarget.value)} />
|
|
327
|
+
- </WaffleCard>
|
|
328
|
+
- </WaffleSettingsSection>
|
|
329
|
+
- </WaffleSettingsPage>
|
|
330
|
+
+ <MockingbirdTextArea rows={16} value={state.createText} onInput={(event) => setState("createText", event.currentTarget.value)} />
|
|
331
|
+
+ </MockingbirdCard>
|
|
332
|
+
+ </MockingbirdSettingsSection>
|
|
333
|
+
+ </MockingbirdSettingsPage>
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
diff --git a/packages/app/src/components/settings-heartbeat.tsx b/packages/app/src/components/settings-heartbeat.tsx
|
|
337
|
+
index 95a1770cc..628fda355 100644
|
|
338
|
+
--- a/packages/app/src/components/settings-heartbeat.tsx
|
|
339
|
+
+++ b/packages/app/src/components/settings-heartbeat.tsx
|
|
340
|
+
@@ -3,17 +3,17 @@ import { Switch } from "@opencode-ai/ui/switch"
|
|
341
|
+
import { showToast } from "@opencode-ai/ui/toast"
|
|
342
|
+
import { onMount, Show, type Component } from "solid-js"
|
|
343
|
+
import { createStore } from "solid-js/store"
|
|
344
|
+
-import { waffleJson } from "@/utils/waffle"
|
|
345
|
+
+import { mockingbirdJson } from "@/utils/mockingbird"
|
|
346
|
+
import {
|
|
347
|
+
- WaffleCard,
|
|
348
|
+
- WaffleInput,
|
|
349
|
+
- WaffleMetaRow,
|
|
350
|
+
- WaffleNotice,
|
|
351
|
+
- WaffleSettingsPage,
|
|
352
|
+
- WaffleSettingsSection,
|
|
353
|
+
- WaffleTextArea,
|
|
354
|
+
- WaffleToolbar,
|
|
355
|
+
-} from "./settings-waffle-shared"
|
|
356
|
+
+ MockingbirdCard,
|
|
357
|
+
+ MockingbirdInput,
|
|
358
|
+
+ MockingbirdMetaRow,
|
|
359
|
+
+ MockingbirdNotice,
|
|
360
|
+
+ MockingbirdSettingsPage,
|
|
361
|
+
+ MockingbirdSettingsSection,
|
|
362
|
+
+ MockingbirdTextArea,
|
|
363
|
+
+ MockingbirdToolbar,
|
|
364
|
+
+} from "./settings-mockingbird-shared"
|
|
365
|
+
|
|
366
|
+
type HeartbeatActiveHours = {
|
|
367
|
+
start: string
|
|
368
|
+
@@ -168,8 +168,8 @@ export const SettingsHeartbeat: Component = () => {
|
|
369
|
+
setState("error", "")
|
|
370
|
+
try {
|
|
371
|
+
const [heartbeat, runtime] = await Promise.all([
|
|
372
|
+
- waffleJson<HeartbeatStatusPayload>("/api/waffle/heartbeat"),
|
|
373
|
+
- waffleJson<RuntimePayload>("/api/waffle/runtime/config"),
|
|
374
|
+
+ mockingbirdJson<HeartbeatStatusPayload>("/api/mockingbird/heartbeat"),
|
|
375
|
+
+ mockingbirdJson<RuntimePayload>("/api/mockingbird/runtime/config"),
|
|
376
|
+
])
|
|
377
|
+
setState("status", heartbeat.heartbeat)
|
|
378
|
+
setState("runtimeHash", runtime.hash)
|
|
379
|
+
@@ -194,7 +194,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
380
|
+
setState("saving", true)
|
|
381
|
+
setState("error", "")
|
|
382
|
+
try {
|
|
383
|
+
- const runtime = await waffleJson<RuntimePayload>("/api/waffle/runtime/config", {
|
|
384
|
+
+ const runtime = await mockingbirdJson<RuntimePayload>("/api/mockingbird/runtime/config", {
|
|
385
|
+
method: "PATCH",
|
|
386
|
+
body: JSON.stringify({
|
|
387
|
+
patch: {
|
|
388
|
+
@@ -224,7 +224,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
389
|
+
setState("running", true)
|
|
390
|
+
setState("error", "")
|
|
391
|
+
try {
|
|
392
|
+
- const payload = await waffleJson<HeartbeatStatusPayload>("/api/waffle/heartbeat/run", {
|
|
393
|
+
+ const payload = await mockingbirdJson<HeartbeatStatusPayload>("/api/mockingbird/heartbeat/run", {
|
|
394
|
+
method: "POST",
|
|
395
|
+
})
|
|
396
|
+
setState("status", payload.heartbeat)
|
|
397
|
+
@@ -246,11 +246,11 @@ export const SettingsHeartbeat: Component = () => {
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
return (
|
|
401
|
+
- <WaffleSettingsPage
|
|
402
|
+
+ <MockingbirdSettingsPage
|
|
403
|
+
title="Heartbeat"
|
|
404
|
+
description="Monitor the dedicated heartbeat session, control its schedule, and choose its model explicitly."
|
|
405
|
+
actions={
|
|
406
|
+
- <WaffleToolbar>
|
|
407
|
+
+ <MockingbirdToolbar>
|
|
408
|
+
<Button variant="ghost" size="large" onClick={() => void load()} disabled={state.loading || state.saving || state.running}>
|
|
409
|
+
Refresh
|
|
410
|
+
</Button>
|
|
411
|
+
@@ -260,46 +260,46 @@ export const SettingsHeartbeat: Component = () => {
|
|
412
|
+
<Button size="large" onClick={() => void save()} disabled={state.loading || state.saving || state.running}>
|
|
413
|
+
Save
|
|
414
|
+
</Button>
|
|
415
|
+
- </WaffleToolbar>
|
|
416
|
+
+ </MockingbirdToolbar>
|
|
417
|
+
}
|
|
418
|
+
>
|
|
419
|
+
<Show when={state.error}>
|
|
420
|
+
- <WaffleNotice tone="error">{state.error}</WaffleNotice>
|
|
421
|
+
+ <MockingbirdNotice tone="error">{state.error}</MockingbirdNotice>
|
|
422
|
+
</Show>
|
|
423
|
+
|
|
424
|
+
<Show when={state.status}>
|
|
425
|
+
{(status) => (
|
|
426
|
+
<>
|
|
427
|
+
- <WaffleSettingsSection title="Status" description="Current scheduler state for the dedicated Heartbeat session.">
|
|
428
|
+
- <WaffleMetaRow label="Config file" value={state.runtimePath || "Unavailable"} />
|
|
429
|
+
- <WaffleMetaRow label="Enabled" value={status().config.enabled ? "Yes" : "No"} />
|
|
430
|
+
- <WaffleMetaRow label="Session id" value={status().state.sessionId ?? "Not created yet"} />
|
|
431
|
+
- <WaffleMetaRow label="Currently running" value={status().state.running ? "Yes" : "No"} />
|
|
432
|
+
- <WaffleMetaRow label="Last run" value={formatTimestamp(status().state.lastRunAt)} />
|
|
433
|
+
- <WaffleMetaRow label="Next due" value={formatTimestamp(status().nextDueAt)} />
|
|
434
|
+
- <WaffleMetaRow label="Last result" value={formatResult(status().state.lastResult)} />
|
|
435
|
+
- <WaffleMetaRow label="Last updated" value={formatTimestamp(status().state.updatedAt)} />
|
|
436
|
+
- </WaffleSettingsSection>
|
|
437
|
+
+ <MockingbirdSettingsSection title="Status" description="Current scheduler state for the dedicated Heartbeat session.">
|
|
438
|
+
+ <MockingbirdMetaRow label="Config file" value={state.runtimePath || "Unavailable"} />
|
|
439
|
+
+ <MockingbirdMetaRow label="Enabled" value={status().config.enabled ? "Yes" : "No"} />
|
|
440
|
+
+ <MockingbirdMetaRow label="Session id" value={status().state.sessionId ?? "Not created yet"} />
|
|
441
|
+
+ <MockingbirdMetaRow label="Currently running" value={status().state.running ? "Yes" : "No"} />
|
|
442
|
+
+ <MockingbirdMetaRow label="Last run" value={formatTimestamp(status().state.lastRunAt)} />
|
|
443
|
+
+ <MockingbirdMetaRow label="Next due" value={formatTimestamp(status().nextDueAt)} />
|
|
444
|
+
+ <MockingbirdMetaRow label="Last result" value={formatResult(status().state.lastResult)} />
|
|
445
|
+
+ <MockingbirdMetaRow label="Last updated" value={formatTimestamp(status().state.updatedAt)} />
|
|
446
|
+
+ </MockingbirdSettingsSection>
|
|
447
|
+
|
|
448
|
+
<Show when={status().state.lastError}>
|
|
449
|
+
- <WaffleNotice tone="error">{status().state.lastError ?? ""}</WaffleNotice>
|
|
450
|
+
+ <MockingbirdNotice tone="error">{status().state.lastError ?? ""}</MockingbirdNotice>
|
|
451
|
+
</Show>
|
|
452
|
+
|
|
453
|
+
<Show when={status().state.lastResponse}>
|
|
454
|
+
- <WaffleSettingsSection title="Last response" description="Most recent heartbeat response captured from the dedicated session.">
|
|
455
|
+
- <WaffleCard>
|
|
456
|
+
+ <MockingbirdSettingsSection title="Last response" description="Most recent heartbeat response captured from the dedicated session.">
|
|
457
|
+
+ <MockingbirdCard>
|
|
458
|
+
<div class="text-13-regular text-text-strong whitespace-pre-wrap break-words">
|
|
459
|
+
{status().state.lastResponse}
|
|
460
|
+
</div>
|
|
461
|
+
- </WaffleCard>
|
|
462
|
+
- </WaffleSettingsSection>
|
|
463
|
+
+ </MockingbirdCard>
|
|
464
|
+
+ </MockingbirdSettingsSection>
|
|
465
|
+
</Show>
|
|
466
|
+
</>
|
|
467
|
+
)}
|
|
468
|
+
</Show>
|
|
469
|
+
|
|
470
|
+
- <WaffleSettingsSection title="Controls" description="Choose whether heartbeat runs, how often it runs, and which model it uses.">
|
|
471
|
+
- <WaffleCard>
|
|
472
|
+
+ <MockingbirdSettingsSection title="Controls" description="Choose whether heartbeat runs, how often it runs, and which model it uses.">
|
|
473
|
+
+ <MockingbirdCard>
|
|
474
|
+
<div class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-border-weak-base bg-surface-base px-4 py-3">
|
|
475
|
+
<div class="flex flex-col gap-1">
|
|
476
|
+
<div class="text-13-medium text-text-strong">Heartbeat enabled</div>
|
|
477
|
+
@@ -313,7 +313,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
478
|
+
<div class="grid gap-4 sm:grid-cols-2">
|
|
479
|
+
<div class="flex flex-col gap-2">
|
|
480
|
+
<span class="text-12-medium text-text-weak">Model</span>
|
|
481
|
+
- <WaffleInput
|
|
482
|
+
+ <MockingbirdInput
|
|
483
|
+
value={state.form.model}
|
|
484
|
+
placeholder="openai/gpt-5.4"
|
|
485
|
+
onInput={(event) => setState("form", "model", event.currentTarget.value)}
|
|
486
|
+
@@ -321,7 +321,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
487
|
+
</div>
|
|
488
|
+
<div class="flex flex-col gap-2">
|
|
489
|
+
<span class="text-12-medium text-text-weak">Interval</span>
|
|
490
|
+
- <WaffleInput
|
|
491
|
+
+ <MockingbirdInput
|
|
492
|
+
value={state.form.interval}
|
|
493
|
+
placeholder="15m"
|
|
494
|
+
onInput={(event) => setState("form", "interval", event.currentTarget.value)}
|
|
495
|
+
@@ -329,7 +329,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
496
|
+
</div>
|
|
497
|
+
<div class="flex flex-col gap-2">
|
|
498
|
+
<span class="text-12-medium text-text-weak">Agent id</span>
|
|
499
|
+
- <WaffleInput
|
|
500
|
+
+ <MockingbirdInput
|
|
501
|
+
value={state.form.agentId}
|
|
502
|
+
placeholder="build"
|
|
503
|
+
onInput={(event) => setState("form", "agentId", event.currentTarget.value)}
|
|
504
|
+
@@ -337,7 +337,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
505
|
+
</div>
|
|
506
|
+
<div class="flex flex-col gap-2">
|
|
507
|
+
<span class="text-12-medium text-text-weak">Ack max chars</span>
|
|
508
|
+
- <WaffleInput
|
|
509
|
+
+ <MockingbirdInput
|
|
510
|
+
type="number"
|
|
511
|
+
min="1"
|
|
512
|
+
value={state.form.ackMaxChars}
|
|
513
|
+
@@ -345,11 +345,11 @@ export const SettingsHeartbeat: Component = () => {
|
|
514
|
+
/>
|
|
515
|
+
</div>
|
|
516
|
+
</div>
|
|
517
|
+
- </WaffleCard>
|
|
518
|
+
- </WaffleSettingsSection>
|
|
519
|
+
+ </MockingbirdCard>
|
|
520
|
+
+ </MockingbirdSettingsSection>
|
|
521
|
+
|
|
522
|
+
- <WaffleSettingsSection title="Active hours" description="Optionally restrict heartbeat runs to a daily time window.">
|
|
523
|
+
- <WaffleCard>
|
|
524
|
+
+ <MockingbirdSettingsSection title="Active hours" description="Optionally restrict heartbeat runs to a daily time window.">
|
|
525
|
+
+ <MockingbirdCard>
|
|
526
|
+
<div class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-border-weak-base bg-surface-base px-4 py-3">
|
|
527
|
+
<div class="flex flex-col gap-1">
|
|
528
|
+
<div class="text-13-medium text-text-strong">Restrict to active hours</div>
|
|
529
|
+
@@ -368,7 +368,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
530
|
+
<div class="grid gap-4 sm:grid-cols-3">
|
|
531
|
+
<div class="flex flex-col gap-2">
|
|
532
|
+
<span class="text-12-medium text-text-weak">Start</span>
|
|
533
|
+
- <WaffleInput
|
|
534
|
+
+ <MockingbirdInput
|
|
535
|
+
value={state.form.activeStart}
|
|
536
|
+
placeholder="09:00"
|
|
537
|
+
onInput={(event) => setState("form", "activeStart", event.currentTarget.value)}
|
|
538
|
+
@@ -376,7 +376,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
539
|
+
</div>
|
|
540
|
+
<div class="flex flex-col gap-2">
|
|
541
|
+
<span class="text-12-medium text-text-weak">End</span>
|
|
542
|
+
- <WaffleInput
|
|
543
|
+
+ <MockingbirdInput
|
|
544
|
+
value={state.form.activeEnd}
|
|
545
|
+
placeholder="17:00"
|
|
546
|
+
onInput={(event) => setState("form", "activeEnd", event.currentTarget.value)}
|
|
547
|
+
@@ -384,7 +384,7 @@ export const SettingsHeartbeat: Component = () => {
|
|
548
|
+
</div>
|
|
549
|
+
<div class="flex flex-col gap-2">
|
|
550
|
+
<span class="text-12-medium text-text-weak">Timezone</span>
|
|
551
|
+
- <WaffleInput
|
|
552
|
+
+ <MockingbirdInput
|
|
553
|
+
value={state.form.activeTimezone}
|
|
554
|
+
placeholder="America/Chicago"
|
|
555
|
+
onInput={(event) => setState("form", "activeTimezone", event.currentTarget.value)}
|
|
556
|
+
@@ -392,18 +392,18 @@ export const SettingsHeartbeat: Component = () => {
|
|
557
|
+
</div>
|
|
558
|
+
</div>
|
|
559
|
+
</Show>
|
|
560
|
+
- </WaffleCard>
|
|
561
|
+
- </WaffleSettingsSection>
|
|
562
|
+
+ </MockingbirdCard>
|
|
563
|
+
+ </MockingbirdSettingsSection>
|
|
564
|
+
|
|
565
|
+
- <WaffleSettingsSection title="Prompt" description="This prompt runs in the visible Heartbeat session whenever the scheduler fires.">
|
|
566
|
+
- <WaffleCard>
|
|
567
|
+
- <WaffleTextArea
|
|
568
|
+
+ <MockingbirdSettingsSection title="Prompt" description="This prompt runs in the visible Heartbeat session whenever the scheduler fires.">
|
|
569
|
+
+ <MockingbirdCard>
|
|
570
|
+
+ <MockingbirdTextArea
|
|
571
|
+
rows={12}
|
|
572
|
+
value={state.form.prompt}
|
|
573
|
+
onInput={(event) => setState("form", "prompt", event.currentTarget.value)}
|
|
574
|
+
/>
|
|
575
|
+
- </WaffleCard>
|
|
576
|
+
- </WaffleSettingsSection>
|
|
577
|
+
- </WaffleSettingsPage>
|
|
578
|
+
+ </MockingbirdCard>
|
|
579
|
+
+ </MockingbirdSettingsSection>
|
|
580
|
+
+ </MockingbirdSettingsPage>
|
|
581
|
+
)
|
|
582
|
+
}
|
|
583
|
+
diff --git a/packages/app/src/components/settings-mcp.tsx b/packages/app/src/components/settings-mcp.tsx
|
|
584
|
+
index 88abc0a06..26bc59c19 100644
|
|
585
|
+
--- a/packages/app/src/components/settings-mcp.tsx
|
|
586
|
+
+++ b/packages/app/src/components/settings-mcp.tsx
|
|
587
|
+
@@ -2,8 +2,8 @@ import { Button } from "@opencode-ai/ui/button"
|
|
588
|
+
import { showToast } from "@opencode-ai/ui/toast"
|
|
589
|
+
import { For, onMount, Show, type Component } from "solid-js"
|
|
590
|
+
import { createStore } from "solid-js/store"
|
|
591
|
+
-import { prettyJson, waffleJson } from "@/utils/waffle"
|
|
592
|
+
-import { WaffleCard, WaffleNotice, WaffleSettingsPage, WaffleSettingsSection, WaffleTextArea, WaffleToolbar } from "./settings-waffle-shared"
|
|
593
|
+
+import { prettyJson, mockingbirdJson } from "@/utils/mockingbird"
|
|
594
|
+
+import { MockingbirdCard, MockingbirdNotice, MockingbirdSettingsPage, MockingbirdSettingsSection, MockingbirdTextArea, MockingbirdToolbar } from "./settings-mockingbird-shared"
|
|
595
|
+
|
|
596
|
+
type McpServer =
|
|
597
|
+
| {
|
|
598
|
+
@@ -51,7 +51,7 @@ export const SettingsMcp: Component = () => {
|
|
599
|
+
setState("loading", true)
|
|
600
|
+
setState("error", "")
|
|
601
|
+
try {
|
|
602
|
+
- const payload = await waffleJson<McpPayload>("/api/waffle/mcp")
|
|
603
|
+
+ const payload = await mockingbirdJson<McpPayload>("/api/mockingbird/mcp")
|
|
604
|
+
setState("payload", payload)
|
|
605
|
+
setState("text", prettyJson(payload.servers))
|
|
606
|
+
} catch (error) {
|
|
607
|
+
@@ -78,7 +78,7 @@ export const SettingsMcp: Component = () => {
|
|
608
|
+
setState("saving", true)
|
|
609
|
+
setState("error", "")
|
|
610
|
+
try {
|
|
611
|
+
- const payload = await waffleJson<McpPayload>("/api/waffle/mcp", {
|
|
612
|
+
+ const payload = await mockingbirdJson<McpPayload>("/api/mockingbird/mcp", {
|
|
613
|
+
method: "PUT",
|
|
614
|
+
body: JSON.stringify({ servers: parsed }),
|
|
615
|
+
})
|
|
616
|
+
@@ -99,8 +99,8 @@ export const SettingsMcp: Component = () => {
|
|
617
|
+
async function runAction(id: string, action: "connect" | "disconnect" | "auth/start" | "auth/remove") {
|
|
618
|
+
setState("busyId", id)
|
|
619
|
+
try {
|
|
620
|
+
- const payload = await waffleJson<{ status: McpStatusMap; authorizationUrl?: string }>(
|
|
621
|
+
- `/api/waffle/mcp/${encodeURIComponent(id)}/${action}`,
|
|
622
|
+
+ const payload = await mockingbirdJson<{ status: McpStatusMap; authorizationUrl?: string }>(
|
|
623
|
+
+ `/api/mockingbird/mcp/${encodeURIComponent(id)}/${action}`,
|
|
624
|
+
{
|
|
625
|
+
method: "POST",
|
|
626
|
+
},
|
|
627
|
+
@@ -123,25 +123,25 @@ export const SettingsMcp: Component = () => {
|
|
628
|
+
const statusFor = (id: string) => state.payload?.status?.[id]?.status ?? "unknown"
|
|
629
|
+
|
|
630
|
+
return (
|
|
631
|
+
- <WaffleSettingsPage
|
|
632
|
+
+ <MockingbirdSettingsPage
|
|
633
|
+
title="MCP"
|
|
634
|
+
description="Edit MCP server definitions and drive connection or auth flows through Agent Mockingbird's same-origin APIs."
|
|
635
|
+
actions={
|
|
636
|
+
- <WaffleToolbar>
|
|
637
|
+
+ <MockingbirdToolbar>
|
|
638
|
+
<Button variant="ghost" size="large" onClick={() => void load()} disabled={state.loading || state.saving}>
|
|
639
|
+
Refresh
|
|
640
|
+
</Button>
|
|
641
|
+
<Button size="large" onClick={() => void save()} disabled={state.loading || state.saving}>
|
|
642
|
+
Save
|
|
643
|
+
</Button>
|
|
644
|
+
- </WaffleToolbar>
|
|
645
|
+
+ </MockingbirdToolbar>
|
|
646
|
+
}
|
|
647
|
+
>
|
|
648
|
+
<Show when={state.error}>
|
|
649
|
+
- <WaffleNotice tone="error">{state.error}</WaffleNotice>
|
|
650
|
+
+ <MockingbirdNotice tone="error">{state.error}</MockingbirdNotice>
|
|
651
|
+
</Show>
|
|
652
|
+
|
|
653
|
+
- <WaffleSettingsSection title="Configured servers" description="Connection status and auth actions for configured MCP servers.">
|
|
654
|
+
+ <MockingbirdSettingsSection title="Configured servers" description="Connection status and auth actions for configured MCP servers.">
|
|
655
|
+
<Show
|
|
656
|
+
when={(state.payload?.servers.length ?? 0) > 0}
|
|
657
|
+
fallback={<div class="px-4 py-4 text-14-regular text-text-weak">No MCP servers configured.</div>}
|
|
658
|
+
@@ -186,18 +186,18 @@ export const SettingsMcp: Component = () => {
|
|
659
|
+
)}
|
|
660
|
+
</For>
|
|
661
|
+
</Show>
|
|
662
|
+
- </WaffleSettingsSection>
|
|
663
|
+
+ </MockingbirdSettingsSection>
|
|
664
|
+
|
|
665
|
+
- <WaffleSettingsSection title="Server editor" description="Edit the full MCP server array as JSON.">
|
|
666
|
+
- <WaffleCard>
|
|
667
|
+
- <WaffleTextArea
|
|
668
|
+
+ <MockingbirdSettingsSection title="Server editor" description="Edit the full MCP server array as JSON.">
|
|
669
|
+
+ <MockingbirdCard>
|
|
670
|
+
+ <MockingbirdTextArea
|
|
671
|
+
rows={22}
|
|
672
|
+
value={state.text}
|
|
673
|
+
onInput={(event) => setState("text", event.currentTarget.value)}
|
|
674
|
+
spellcheck={false}
|
|
675
|
+
/>
|
|
676
|
+
- </WaffleCard>
|
|
677
|
+
- </WaffleSettingsSection>
|
|
678
|
+
- </WaffleSettingsPage>
|
|
679
|
+
+ </MockingbirdCard>
|
|
680
|
+
+ </MockingbirdSettingsSection>
|
|
681
|
+
+ </MockingbirdSettingsPage>
|
|
682
|
+
)
|
|
683
|
+
}
|
|
684
|
+
diff --git a/packages/app/src/components/settings-waffle-shared.tsx b/packages/app/src/components/settings-mockingbird-shared.tsx
|
|
685
|
+
similarity index 85%
|
|
686
|
+
rename from packages/app/src/components/settings-waffle-shared.tsx
|
|
687
|
+
rename to packages/app/src/components/settings-mockingbird-shared.tsx
|
|
688
|
+
index 64ece4b04..6955f903c 100644
|
|
689
|
+
--- a/packages/app/src/components/settings-waffle-shared.tsx
|
|
690
|
+
+++ b/packages/app/src/components/settings-mockingbird-shared.tsx
|
|
691
|
+
@@ -1,6 +1,6 @@
|
|
692
|
+
import { type JSX, type ParentProps, Show } from "solid-js"
|
|
693
|
+
|
|
694
|
+
-export function WaffleSettingsPage(
|
|
695
|
+
+export function MockingbirdSettingsPage(
|
|
696
|
+
props: ParentProps<{
|
|
697
|
+
title: string
|
|
698
|
+
description?: string
|
|
699
|
+
@@ -28,7 +28,7 @@ export function WaffleSettingsPage(
|
|
700
|
+
)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
-export function WaffleSettingsSection(
|
|
704
|
+
+export function MockingbirdSettingsSection(
|
|
705
|
+
props: ParentProps<{
|
|
706
|
+
title: string
|
|
707
|
+
description?: string
|
|
708
|
+
@@ -53,7 +53,7 @@ export function WaffleSettingsSection(
|
|
709
|
+
)
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
-export function WaffleMetaRow(props: { label: string; value: string | JSX.Element }) {
|
|
713
|
+
+export function MockingbirdMetaRow(props: { label: string; value: string | JSX.Element }) {
|
|
714
|
+
return (
|
|
715
|
+
<div class="flex flex-col gap-1 px-4 py-3 border-b border-border-weak-base last:border-none">
|
|
716
|
+
<span class="text-12-medium text-text-weak">{props.label}</span>
|
|
717
|
+
@@ -62,11 +62,11 @@ export function WaffleMetaRow(props: { label: string; value: string | JSX.Elemen
|
|
718
|
+
)
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
-export function WaffleToolbar(props: ParentProps) {
|
|
722
|
+
+export function MockingbirdToolbar(props: ParentProps) {
|
|
723
|
+
return <div class="flex flex-wrap items-center gap-2">{props.children}</div>
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
-export function WaffleNotice(props: { tone?: "error" | "success" | "info"; children: JSX.Element }) {
|
|
727
|
+
+export function MockingbirdNotice(props: { tone?: "error" | "success" | "info"; children: JSX.Element }) {
|
|
728
|
+
const tone = () => props.tone ?? "info"
|
|
729
|
+
return (
|
|
730
|
+
<div
|
|
731
|
+
@@ -82,7 +82,7 @@ export function WaffleNotice(props: { tone?: "error" | "success" | "info"; child
|
|
732
|
+
)
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
-export function WaffleInput(props: JSX.InputHTMLAttributes<HTMLInputElement>) {
|
|
736
|
+
+export function MockingbirdInput(props: JSX.InputHTMLAttributes<HTMLInputElement>) {
|
|
737
|
+
return (
|
|
738
|
+
<input
|
|
739
|
+
{...props}
|
|
740
|
+
@@ -93,7 +93,7 @@ export function WaffleInput(props: JSX.InputHTMLAttributes<HTMLInputElement>) {
|
|
741
|
+
)
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
-export function WaffleTextArea(props: JSX.TextareaHTMLAttributes<HTMLTextAreaElement>) {
|
|
745
|
+
+export function MockingbirdTextArea(props: JSX.TextareaHTMLAttributes<HTMLTextAreaElement>) {
|
|
746
|
+
return (
|
|
747
|
+
<textarea
|
|
748
|
+
{...props}
|
|
749
|
+
@@ -104,7 +104,7 @@ export function WaffleTextArea(props: JSX.TextareaHTMLAttributes<HTMLTextAreaEle
|
|
750
|
+
)
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
-export function WaffleCard(props: ParentProps<{ footer?: JSX.Element }>) {
|
|
754
|
+
+export function MockingbirdCard(props: ParentProps<{ footer?: JSX.Element }>) {
|
|
755
|
+
return (
|
|
756
|
+
<div class="rounded-lg border border-border-weak-base bg-background-base overflow-hidden">
|
|
757
|
+
<div class="p-4 flex flex-col gap-4">{props.children}</div>
|
|
758
|
+
diff --git a/packages/app/src/components/settings-runtime.tsx b/packages/app/src/components/settings-runtime.tsx
|
|
759
|
+
index fd091697e..808430278 100644
|
|
760
|
+
--- a/packages/app/src/components/settings-runtime.tsx
|
|
761
|
+
+++ b/packages/app/src/components/settings-runtime.tsx
|
|
762
|
+
@@ -2,8 +2,8 @@ import { Button } from "@opencode-ai/ui/button"
|
|
763
|
+
import { showToast } from "@opencode-ai/ui/toast"
|
|
764
|
+
import { onMount, Show, type Component } from "solid-js"
|
|
765
|
+
import { createStore } from "solid-js/store"
|
|
766
|
+
-import { prettyJson, waffleJson } from "@/utils/waffle"
|
|
767
|
+
-import { WaffleCard, WaffleMetaRow, WaffleNotice, WaffleSettingsPage, WaffleSettingsSection, WaffleTextArea, WaffleToolbar } from "./settings-waffle-shared"
|
|
768
|
+
+import { prettyJson, mockingbirdJson } from "@/utils/mockingbird"
|
|
769
|
+
+import { MockingbirdCard, MockingbirdMetaRow, MockingbirdNotice, MockingbirdSettingsPage, MockingbirdSettingsSection, MockingbirdTextArea, MockingbirdToolbar } from "./settings-mockingbird-shared"
|
|
770
|
+
|
|
771
|
+
type RuntimePayload = {
|
|
772
|
+
hash: string
|
|
773
|
+
@@ -29,7 +29,7 @@ export const SettingsRuntime: Component = () => {
|
|
774
|
+
setState("loading", true)
|
|
775
|
+
setState("error", "")
|
|
776
|
+
try {
|
|
777
|
+
- const payload = await waffleJson<RuntimePayload>("/api/waffle/runtime/config")
|
|
778
|
+
+ const payload = await mockingbirdJson<RuntimePayload>("/api/mockingbird/runtime/config")
|
|
779
|
+
setState("payload", payload)
|
|
780
|
+
setState("text", prettyJson(payload.config))
|
|
781
|
+
} catch (error) {
|
|
782
|
+
@@ -51,7 +51,7 @@ export const SettingsRuntime: Component = () => {
|
|
783
|
+
setState("saving", true)
|
|
784
|
+
setState("error", "")
|
|
785
|
+
try {
|
|
786
|
+
- const payload = await waffleJson<RuntimePayload>("/api/waffle/runtime/config/replace", {
|
|
787
|
+
+ const payload = await mockingbirdJson<RuntimePayload>("/api/mockingbird/runtime/config/replace", {
|
|
788
|
+
method: "POST",
|
|
789
|
+
body: JSON.stringify({
|
|
790
|
+
config: parsed,
|
|
791
|
+
@@ -77,44 +77,44 @@ export const SettingsRuntime: Component = () => {
|
|
792
|
+
})
|
|
793
|
+
|
|
794
|
+
return (
|
|
795
|
+
- <WaffleSettingsPage
|
|
796
|
+
+ <MockingbirdSettingsPage
|
|
797
|
+
title="Runtime"
|
|
798
|
+
description="Edit Agent Mockingbird runtime settings owned outside OpenCode's workspace config."
|
|
799
|
+
actions={
|
|
800
|
+
- <WaffleToolbar>
|
|
801
|
+
+ <MockingbirdToolbar>
|
|
802
|
+
<Button variant="ghost" size="large" onClick={() => void load()} disabled={state.loading || state.saving}>
|
|
803
|
+
Refresh
|
|
804
|
+
</Button>
|
|
805
|
+
<Button size="large" onClick={() => void save()} disabled={state.loading || state.saving}>
|
|
806
|
+
Save
|
|
807
|
+
</Button>
|
|
808
|
+
- </WaffleToolbar>
|
|
809
|
+
+ </MockingbirdToolbar>
|
|
810
|
+
}
|
|
811
|
+
>
|
|
812
|
+
<Show when={state.error}>
|
|
813
|
+
- <WaffleNotice tone="error">{state.error}</WaffleNotice>
|
|
814
|
+
+ <MockingbirdNotice tone="error">{state.error}</MockingbirdNotice>
|
|
815
|
+
</Show>
|
|
816
|
+
|
|
817
|
+
<Show when={state.payload}>
|
|
818
|
+
{(payload) => (
|
|
819
|
+
- <WaffleSettingsSection title="Config metadata">
|
|
820
|
+
- <WaffleMetaRow label="Config file" value={payload().path} />
|
|
821
|
+
- <WaffleMetaRow label="Pinned workspace" value={payload().config.workspace.pinnedDirectory} />
|
|
822
|
+
- <WaffleMetaRow label="Revision hash" value={payload().hash} />
|
|
823
|
+
- </WaffleSettingsSection>
|
|
824
|
+
+ <MockingbirdSettingsSection title="Config metadata">
|
|
825
|
+
+ <MockingbirdMetaRow label="Config file" value={payload().path} />
|
|
826
|
+
+ <MockingbirdMetaRow label="Pinned workspace" value={payload().config.workspace.pinnedDirectory} />
|
|
827
|
+
+ <MockingbirdMetaRow label="Revision hash" value={payload().hash} />
|
|
828
|
+
+ </MockingbirdSettingsSection>
|
|
829
|
+
)}
|
|
830
|
+
</Show>
|
|
831
|
+
|
|
832
|
+
- <WaffleSettingsSection title="Config editor" description="Replace the current Agent Mockingbird config payload with JSON.">
|
|
833
|
+
- <WaffleCard>
|
|
834
|
+
- <WaffleTextArea
|
|
835
|
+
+ <MockingbirdSettingsSection title="Config editor" description="Replace the current Agent Mockingbird config payload with JSON.">
|
|
836
|
+
+ <MockingbirdCard>
|
|
837
|
+
+ <MockingbirdTextArea
|
|
838
|
+
rows={22}
|
|
839
|
+
value={state.text}
|
|
840
|
+
onInput={(event) => setState("text", event.currentTarget.value)}
|
|
841
|
+
spellcheck={false}
|
|
842
|
+
/>
|
|
843
|
+
- </WaffleCard>
|
|
844
|
+
- </WaffleSettingsSection>
|
|
845
|
+
- </WaffleSettingsPage>
|
|
846
|
+
+ </MockingbirdCard>
|
|
847
|
+
+ </MockingbirdSettingsSection>
|
|
848
|
+
+ </MockingbirdSettingsPage>
|
|
849
|
+
)
|
|
850
|
+
}
|
|
851
|
+
diff --git a/packages/app/src/components/settings-skills.tsx b/packages/app/src/components/settings-skills.tsx
|
|
852
|
+
index 2254d384c..ca7c7b3cf 100644
|
|
853
|
+
--- a/packages/app/src/components/settings-skills.tsx
|
|
854
|
+
+++ b/packages/app/src/components/settings-skills.tsx
|
|
855
|
+
@@ -3,8 +3,8 @@ import { Switch } from "@opencode-ai/ui/switch"
|
|
856
|
+
import { showToast } from "@opencode-ai/ui/toast"
|
|
857
|
+
import { createSignal, For, onMount, Show, type Component } from "solid-js"
|
|
858
|
+
import { createStore } from "solid-js/store"
|
|
859
|
+
-import { WaffleCard, WaffleInput, WaffleMetaRow, WaffleNotice, WaffleSettingsPage, WaffleSettingsSection, WaffleTextArea, WaffleToolbar } from "./settings-waffle-shared"
|
|
860
|
+
-import { waffleJson } from "@/utils/waffle"
|
|
861
|
+
+import { MockingbirdCard, MockingbirdInput, MockingbirdMetaRow, MockingbirdNotice, MockingbirdSettingsPage, MockingbirdSettingsSection, MockingbirdTextArea, MockingbirdToolbar } from "./settings-mockingbird-shared"
|
|
862
|
+
+import { mockingbirdJson } from "@/utils/mockingbird"
|
|
863
|
+
|
|
864
|
+
type SkillEntry = {
|
|
865
|
+
id: string
|
|
866
|
+
@@ -48,7 +48,7 @@ export const SettingsSkills: Component = () => {
|
|
867
|
+
setState("loading", true)
|
|
868
|
+
setState("error", "")
|
|
869
|
+
try {
|
|
870
|
+
- const catalog = await waffleJson<SkillsPayload>("/api/waffle/skills")
|
|
871
|
+
+ const catalog = await mockingbirdJson<SkillsPayload>("/api/mockingbird/skills")
|
|
872
|
+
setState("catalog", catalog)
|
|
873
|
+
} catch (error) {
|
|
874
|
+
const message = error instanceof Error ? error.message : "Failed to load skills"
|
|
875
|
+
@@ -66,7 +66,7 @@ export const SettingsSkills: Component = () => {
|
|
876
|
+
async function toggleSkill(id: string, enabled: boolean) {
|
|
877
|
+
setState("busyId", id)
|
|
878
|
+
try {
|
|
879
|
+
- const next = await waffleJson<SkillsPayload>(`/api/waffle/skills/${encodeURIComponent(id)}`, {
|
|
880
|
+
+ const next = await mockingbirdJson<SkillsPayload>(`/api/mockingbird/skills/${encodeURIComponent(id)}`, {
|
|
881
|
+
method: "PATCH",
|
|
882
|
+
body: JSON.stringify({ enabled }),
|
|
883
|
+
})
|
|
884
|
+
@@ -84,7 +84,7 @@ export const SettingsSkills: Component = () => {
|
|
885
|
+
async function removeSkill(id: string) {
|
|
886
|
+
setState("busyId", id)
|
|
887
|
+
try {
|
|
888
|
+
- const next = await waffleJson<SkillsPayload>(`/api/waffle/skills/${encodeURIComponent(id)}`, {
|
|
889
|
+
+ const next = await mockingbirdJson<SkillsPayload>(`/api/mockingbird/skills/${encodeURIComponent(id)}`, {
|
|
890
|
+
method: "DELETE",
|
|
891
|
+
})
|
|
892
|
+
setState("catalog", next)
|
|
893
|
+
@@ -107,7 +107,7 @@ export const SettingsSkills: Component = () => {
|
|
894
|
+
setState("error", "")
|
|
895
|
+
setState("busyId", "import")
|
|
896
|
+
try {
|
|
897
|
+
- await waffleJson("/api/waffle/skills/import", {
|
|
898
|
+
+ await mockingbirdJson("/api/mockingbird/skills/import", {
|
|
899
|
+
method: "POST",
|
|
900
|
+
body: JSON.stringify({
|
|
901
|
+
id: state.importId,
|
|
902
|
+
@@ -135,30 +135,30 @@ export const SettingsSkills: Component = () => {
|
|
903
|
+
})
|
|
904
|
+
|
|
905
|
+
return (
|
|
906
|
+
- <WaffleSettingsPage
|
|
907
|
+
+ <MockingbirdSettingsPage
|
|
908
|
+
title="Skills"
|
|
909
|
+
description="Manage the workspace skill catalog and import managed skills for the pinned workspace."
|
|
910
|
+
actions={
|
|
911
|
+
- <WaffleToolbar>
|
|
912
|
+
+ <MockingbirdToolbar>
|
|
913
|
+
<Button variant="ghost" size="large" onClick={() => void refresh()} disabled={state.loading}>
|
|
914
|
+
Refresh
|
|
915
|
+
</Button>
|
|
916
|
+
- </WaffleToolbar>
|
|
917
|
+
+ </MockingbirdToolbar>
|
|
918
|
+
}
|
|
919
|
+
>
|
|
920
|
+
<Show when={state.error}>
|
|
921
|
+
- <WaffleNotice tone="error">{state.error}</WaffleNotice>
|
|
922
|
+
+ <MockingbirdNotice tone="error">{state.error}</MockingbirdNotice>
|
|
923
|
+
</Show>
|
|
924
|
+
|
|
925
|
+
<Show when={state.catalog}>
|
|
926
|
+
{(catalog) => (
|
|
927
|
+
<>
|
|
928
|
+
- <WaffleSettingsSection title="Catalog paths">
|
|
929
|
+
- <WaffleMetaRow label="Managed skills path" value={catalog().managedPath} />
|
|
930
|
+
- <WaffleMetaRow label="Disabled skills path" value={catalog().disabledPath} />
|
|
931
|
+
- </WaffleSettingsSection>
|
|
932
|
+
+ <MockingbirdSettingsSection title="Catalog paths">
|
|
933
|
+
+ <MockingbirdMetaRow label="Managed skills path" value={catalog().managedPath} />
|
|
934
|
+
+ <MockingbirdMetaRow label="Disabled skills path" value={catalog().disabledPath} />
|
|
935
|
+
+ </MockingbirdSettingsSection>
|
|
936
|
+
|
|
937
|
+
- <WaffleSettingsSection title="Installed skills" description="Enable, disable, or remove managed skills.">
|
|
938
|
+
+ <MockingbirdSettingsSection title="Installed skills" description="Enable, disable, or remove managed skills.">
|
|
939
|
+
<Show
|
|
940
|
+
when={catalog().skills.length > 0}
|
|
941
|
+
fallback={<div class="px-4 py-4 text-14-regular text-text-weak">No managed skills found.</div>}
|
|
942
|
+
@@ -193,10 +193,10 @@ export const SettingsSkills: Component = () => {
|
|
943
|
+
)}
|
|
944
|
+
</For>
|
|
945
|
+
</Show>
|
|
946
|
+
- </WaffleSettingsSection>
|
|
947
|
+
+ </MockingbirdSettingsSection>
|
|
948
|
+
|
|
949
|
+
<Show when={catalog().invalid.length > 0}>
|
|
950
|
+
- <WaffleSettingsSection title="Invalid skills">
|
|
951
|
+
+ <MockingbirdSettingsSection title="Invalid skills">
|
|
952
|
+
<For each={catalog().invalid}>
|
|
953
|
+
{(issue) => (
|
|
954
|
+
<div class="px-4 py-3 border-b border-border-weak-base last:border-none">
|
|
955
|
+
@@ -206,17 +206,17 @@ export const SettingsSkills: Component = () => {
|
|
956
|
+
</div>
|
|
957
|
+
)}
|
|
958
|
+
</For>
|
|
959
|
+
- </WaffleSettingsSection>
|
|
960
|
+
+ </MockingbirdSettingsSection>
|
|
961
|
+
</Show>
|
|
962
|
+
</>
|
|
963
|
+
)}
|
|
964
|
+
</Show>
|
|
965
|
+
|
|
966
|
+
- <WaffleSettingsSection
|
|
967
|
+
+ <MockingbirdSettingsSection
|
|
968
|
+
title="Import skill"
|
|
969
|
+
description="Paste a managed SKILL.md and import it into the pinned workspace."
|
|
970
|
+
>
|
|
971
|
+
- <WaffleCard
|
|
972
|
+
+ <MockingbirdCard
|
|
973
|
+
footer={
|
|
974
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
975
|
+
<label class="flex items-center gap-2 text-13-regular text-text-strong">
|
|
976
|
+
@@ -235,7 +235,7 @@ export const SettingsSkills: Component = () => {
|
|
977
|
+
>
|
|
978
|
+
<div class="flex flex-col gap-2">
|
|
979
|
+
<span class="text-12-medium text-text-weak">Skill id</span>
|
|
980
|
+
- <WaffleInput
|
|
981
|
+
+ <MockingbirdInput
|
|
982
|
+
value={state.importId}
|
|
983
|
+
placeholder="example-skill"
|
|
984
|
+
onInput={(event) => setState("importId", event.currentTarget.value)}
|
|
985
|
+
@@ -243,14 +243,14 @@ export const SettingsSkills: Component = () => {
|
|
986
|
+
</div>
|
|
987
|
+
<div class="flex flex-col gap-2">
|
|
988
|
+
<span class="text-12-medium text-text-weak">SKILL.md content</span>
|
|
989
|
+
- <WaffleTextArea
|
|
990
|
+
+ <MockingbirdTextArea
|
|
991
|
+
rows={14}
|
|
992
|
+
value={state.importContent}
|
|
993
|
+
onInput={(event) => setState("importContent", event.currentTarget.value)}
|
|
994
|
+
/>
|
|
995
|
+
</div>
|
|
996
|
+
- </WaffleCard>
|
|
997
|
+
- </WaffleSettingsSection>
|
|
998
|
+
- </WaffleSettingsPage>
|
|
999
|
+
+ </MockingbirdCard>
|
|
1000
|
+
+ </MockingbirdSettingsSection>
|
|
1001
|
+
+ </MockingbirdSettingsPage>
|
|
1002
|
+
)
|
|
1003
|
+
}
|
|
1004
|
+
diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts
|
|
1005
|
+
index 0bb31bab0..5c6e30b68 100644
|
|
1006
|
+
--- a/packages/app/src/i18n/en.ts
|
|
1007
|
+
+++ b/packages/app/src/i18n/en.ts
|
|
1008
|
+
@@ -703,7 +703,7 @@ export const dict = {
|
|
1009
|
+
|
|
1010
|
+
"settings.section.desktop": "Desktop",
|
|
1011
|
+
"settings.section.server": "Server",
|
|
1012
|
+
- "settings.section.wafflebot": "Wafflebot",
|
|
1013
|
+
+ "settings.section.agent-mockingbird": "Agent Mockingbird",
|
|
1014
|
+
"settings.tab.general": "General",
|
|
1015
|
+
"settings.tab.shortcuts": "Shortcuts",
|
|
1016
|
+
"settings.desktop.section.wsl": "WSL",
|
|
1017
|
+
diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx
|
|
1018
|
+
index 50b6fa5ad..f6c5b7b23 100644
|
|
1019
|
+
--- a/packages/app/src/pages/directory-layout.tsx
|
|
1020
|
+
+++ b/packages/app/src/pages/directory-layout.tsx
|
|
1021
|
+
@@ -11,7 +11,7 @@ import { base64Encode } from "@opencode-ai/util/encode"
|
|
1022
|
+
import { decode64 } from "@/utils/base64"
|
|
1023
|
+
import { showToast } from "@opencode-ai/ui/toast"
|
|
1024
|
+
import { useLanguage } from "@/context/language"
|
|
1025
|
+
-import { readPinnedWorkspace, workspaceHref } from "@/utils/waffle"
|
|
1026
|
+
+import { readPinnedWorkspace, workspaceHref } from "@/utils/mockingbird"
|
|
1027
|
+
function DirectoryDataProvider(props: ParentProps<{ directory: string }>) {
|
|
1028
|
+
const navigate = useNavigate()
|
|
1029
|
+
const sync = useSync()
|
|
1030
|
+
diff --git a/packages/app/src/pages/home.tsx b/packages/app/src/pages/home.tsx
|
|
1031
|
+
index ab5c84329..a556507cb 100644
|
|
1032
|
+
--- a/packages/app/src/pages/home.tsx
|
|
1033
|
+
+++ b/packages/app/src/pages/home.tsx
|
|
1034
|
+
@@ -1,6 +1,6 @@
|
|
1035
|
+
import { useNavigate } from "@solidjs/router"
|
|
1036
|
+
import { createSignal, onMount, Show } from "solid-js"
|
|
1037
|
+
-import { readPinnedWorkspace, workspaceHref } from "@/utils/waffle"
|
|
1038
|
+
+import { readPinnedWorkspace, workspaceHref } from "@/utils/mockingbird"
|
|
1039
|
+
|
|
1040
|
+
export default function Home() {
|
|
1041
|
+
const navigate = useNavigate()
|
|
1042
|
+
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx
|
|
1043
|
+
index 86cfb0b9b..3246eaebc 100644
|
|
1044
|
+
--- a/packages/app/src/pages/layout.tsx
|
|
1045
|
+
+++ b/packages/app/src/pages/layout.tsx
|
|
1046
|
+
@@ -91,7 +91,7 @@ import {
|
|
1047
|
+
} from "./layout/sidebar-workspace"
|
|
1048
|
+
import { ProjectDragOverlay, SortableProject, type ProjectSidebarContext } from "./layout/sidebar-project"
|
|
1049
|
+
import { SidebarContent } from "./layout/sidebar-shell"
|
|
1050
|
+
-import { readPinnedWorkspace } from "@/utils/waffle"
|
|
1051
|
+
+import { readPinnedWorkspace } from "@/utils/mockingbird"
|
|
1052
|
+
|
|
1053
|
+
export default function Layout(props: ParentProps) {
|
|
1054
|
+
const [store, setStore, , ready] = persisted(
|
|
1055
|
+
diff --git a/packages/app/src/utils/waffle.ts b/packages/app/src/utils/mockingbird.ts
|
|
1056
|
+
similarity index 75%
|
|
1057
|
+
rename from packages/app/src/utils/waffle.ts
|
|
1058
|
+
rename to packages/app/src/utils/mockingbird.ts
|
|
1059
|
+
index 79286f66b..c30e7aac8 100644
|
|
1060
|
+
--- a/packages/app/src/utils/waffle.ts
|
|
1061
|
+
+++ b/packages/app/src/utils/mockingbird.ts
|
|
1062
|
+
@@ -1,11 +1,11 @@
|
|
1063
|
+
import { base64Encode } from "@opencode-ai/util/encode"
|
|
1064
|
+
|
|
1065
|
+
-export class WaffleApiError extends Error {
|
|
1066
|
+
+export class MockingbirdApiError extends Error {
|
|
1067
|
+
status: number
|
|
1068
|
+
|
|
1069
|
+
constructor(message: string, status: number) {
|
|
1070
|
+
super(message)
|
|
1071
|
+
- this.name = "WaffleApiError"
|
|
1072
|
+
+ this.name = "MockingbirdApiError"
|
|
1073
|
+
this.status = status
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
@@ -13,13 +13,13 @@ export class WaffleApiError extends Error {
|
|
1077
|
+
async function parseJson<T>(response: Response): Promise<T> {
|
|
1078
|
+
const contentType = response.headers.get("content-type") ?? ""
|
|
1079
|
+
if (!contentType.includes("application/json")) {
|
|
1080
|
+
- throw new WaffleApiError(`Expected JSON response from ${response.url}`, response.status)
|
|
1081
|
+
+ throw new MockingbirdApiError(`Expected JSON response from ${response.url}`, response.status)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
return (await response.json()) as T
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
-export async function waffleJson<T>(path: string, init?: RequestInit): Promise<T> {
|
|
1088
|
+
+export async function mockingbirdJson<T>(path: string, init?: RequestInit): Promise<T> {
|
|
1089
|
+
const response = await fetch(path, {
|
|
1090
|
+
...init,
|
|
1091
|
+
headers: {
|
|
1092
|
+
@@ -36,7 +36,7 @@ export async function waffleJson<T>(path: string, init?: RequestInit): Promise<T
|
|
1093
|
+
} catch {
|
|
1094
|
+
// Preserve the default HTTP status message when the error body is not JSON.
|
|
1095
|
+
}
|
|
1096
|
+
- throw new WaffleApiError(message, response.status)
|
|
1097
|
+
+ throw new MockingbirdApiError(message, response.status)
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
return parseJson<T>(response)
|
|
1101
|
+
@@ -57,5 +57,5 @@ export interface PinnedWorkspacePayload {
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
export function readPinnedWorkspace() {
|
|
1105
|
+
- return waffleJson<PinnedWorkspacePayload>("/api/waffle/runtime/pinned-workspace")
|
|
1106
|
+
+ return mockingbirdJson<PinnedWorkspacePayload>("/api/mockingbird/runtime/pinned-workspace")
|
|
1107
|
+
}
|
|
1108
|
+
--
|
|
1109
|
+
2.53.0
|
|
1110
|
+
|