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.
Files changed (227) hide show
  1. package/.agents/skills/btca-cli/SKILL.md +64 -0
  2. package/.agents/skills/btca-cli/agents/openai.yaml +3 -0
  3. package/.agents/skills/frontend-design/SKILL.md +42 -0
  4. package/.agents/skills/frontend-design/agents/openai.yaml +3 -0
  5. package/.env.example +36 -0
  6. package/.githooks/pre-commit +33 -0
  7. package/.github/workflows/ci.yml +309 -0
  8. package/.opencode/bun.lock +18 -0
  9. package/.opencode/package.json +5 -0
  10. package/.opencode/tools/agent_type_manager.ts +100 -0
  11. package/.opencode/tools/config_manager.ts +87 -0
  12. package/.opencode/tools/cron_manager.ts +145 -0
  13. package/.opencode/tools/memory_get.ts +43 -0
  14. package/.opencode/tools/memory_remember.ts +53 -0
  15. package/.opencode/tools/memory_search.ts +48 -0
  16. package/AGENTS.md +126 -0
  17. package/MEMORY.md +2 -0
  18. package/README.md +451 -0
  19. package/THIRD_PARTY_NOTICES.md +11 -0
  20. package/agent-mockingbird.config.example.json +135 -0
  21. package/apps/server/package.json +32 -0
  22. package/apps/server/src/backend/agents/bootstrapContext.ts +362 -0
  23. package/apps/server/src/backend/agents/openclawImport.test.ts +133 -0
  24. package/apps/server/src/backend/agents/openclawImport.ts +797 -0
  25. package/apps/server/src/backend/agents/opencodeConfig.ts +428 -0
  26. package/apps/server/src/backend/agents/service.ts +10 -0
  27. package/apps/server/src/backend/config/example-config.test.ts +20 -0
  28. package/apps/server/src/backend/config/orchestration.ts +243 -0
  29. package/apps/server/src/backend/config/policy.ts +158 -0
  30. package/apps/server/src/backend/config/schema.test.ts +15 -0
  31. package/apps/server/src/backend/config/schema.ts +391 -0
  32. package/apps/server/src/backend/config/semantic.test.ts +34 -0
  33. package/apps/server/src/backend/config/semantic.ts +149 -0
  34. package/apps/server/src/backend/config/service.test.ts +75 -0
  35. package/apps/server/src/backend/config/service.ts +207 -0
  36. package/apps/server/src/backend/config/smoke.ts +77 -0
  37. package/apps/server/src/backend/config/store.test.ts +123 -0
  38. package/apps/server/src/backend/config/store.ts +581 -0
  39. package/apps/server/src/backend/config/testFixtures.ts +5 -0
  40. package/apps/server/src/backend/config/types.ts +56 -0
  41. package/apps/server/src/backend/contracts/events.ts +320 -0
  42. package/apps/server/src/backend/contracts/runtime.ts +111 -0
  43. package/apps/server/src/backend/cron/executor.ts +435 -0
  44. package/apps/server/src/backend/cron/repository.ts +170 -0
  45. package/apps/server/src/backend/cron/service.ts +660 -0
  46. package/apps/server/src/backend/cron/storage.ts +92 -0
  47. package/apps/server/src/backend/cron/types.ts +138 -0
  48. package/apps/server/src/backend/cron/utils.ts +351 -0
  49. package/apps/server/src/backend/db/client.ts +20 -0
  50. package/apps/server/src/backend/db/migrate.ts +40 -0
  51. package/apps/server/src/backend/db/repository.ts +1762 -0
  52. package/apps/server/src/backend/db/schema.ts +113 -0
  53. package/apps/server/src/backend/db/usageDashboard.test.ts +102 -0
  54. package/apps/server/src/backend/db/wipe.ts +13 -0
  55. package/apps/server/src/backend/defaults.ts +32 -0
  56. package/apps/server/src/backend/env.ts +48 -0
  57. package/apps/server/src/backend/heartbeat/activeHours.ts +45 -0
  58. package/apps/server/src/backend/heartbeat/defaultJob.ts +88 -0
  59. package/apps/server/src/backend/heartbeat/heartbeat.test.ts +110 -0
  60. package/apps/server/src/backend/heartbeat/runtimeService.ts +190 -0
  61. package/apps/server/src/backend/heartbeat/service.ts +176 -0
  62. package/apps/server/src/backend/heartbeat/state.test.ts +63 -0
  63. package/apps/server/src/backend/heartbeat/state.ts +167 -0
  64. package/apps/server/src/backend/heartbeat/types.ts +54 -0
  65. package/apps/server/src/backend/http/boundedQueue.test.ts +49 -0
  66. package/apps/server/src/backend/http/boundedQueue.ts +92 -0
  67. package/apps/server/src/backend/http/parsers.ts +40 -0
  68. package/apps/server/src/backend/http/router.ts +61 -0
  69. package/apps/server/src/backend/http/routes/agentRoutes.ts +67 -0
  70. package/apps/server/src/backend/http/routes/backgroundRoutes.ts +203 -0
  71. package/apps/server/src/backend/http/routes/chatRoutes.ts +107 -0
  72. package/apps/server/src/backend/http/routes/configRoutes.ts +602 -0
  73. package/apps/server/src/backend/http/routes/cronRoutes.ts +221 -0
  74. package/apps/server/src/backend/http/routes/dashboardRoutes.ts +308 -0
  75. package/apps/server/src/backend/http/routes/eventRoutes.ts +7 -0
  76. package/apps/server/src/backend/http/routes/heartbeatRoutes.test.ts +41 -0
  77. package/apps/server/src/backend/http/routes/heartbeatRoutes.ts +28 -0
  78. package/apps/server/src/backend/http/routes/index.ts +101 -0
  79. package/apps/server/src/backend/http/routes/mcpRoutes.ts +213 -0
  80. package/apps/server/src/backend/http/routes/memoryRoutes.ts +154 -0
  81. package/apps/server/src/backend/http/routes/runRoutes.ts +310 -0
  82. package/apps/server/src/backend/http/routes/runtimeRoutes.ts +197 -0
  83. package/apps/server/src/backend/http/routes/skillRoutes.ts +112 -0
  84. package/apps/server/src/backend/http/routes/uiRoutes.test.ts +161 -0
  85. package/apps/server/src/backend/http/routes/uiRoutes.ts +177 -0
  86. package/apps/server/src/backend/http/routes/usageRoutes.test.ts +104 -0
  87. package/apps/server/src/backend/http/routes/usageRoutes.ts +767 -0
  88. package/apps/server/src/backend/http/schemas.ts +64 -0
  89. package/apps/server/src/backend/http/sse.ts +144 -0
  90. package/apps/server/src/backend/integration/backend-core.test.ts +2316 -0
  91. package/apps/server/src/backend/logging/logger.ts +64 -0
  92. package/apps/server/src/backend/mcp/service.ts +326 -0
  93. package/apps/server/src/backend/memory/cli.ts +170 -0
  94. package/apps/server/src/backend/memory/conceptExpansion.test.ts +28 -0
  95. package/apps/server/src/backend/memory/conceptExpansion.ts +80 -0
  96. package/apps/server/src/backend/memory/qmdPort.test.ts +54 -0
  97. package/apps/server/src/backend/memory/qmdPort.ts +61 -0
  98. package/apps/server/src/backend/memory/records.test.ts +66 -0
  99. package/apps/server/src/backend/memory/records.ts +229 -0
  100. package/apps/server/src/backend/memory/service.ts +2012 -0
  101. package/apps/server/src/backend/memory/sqliteVec.ts +58 -0
  102. package/apps/server/src/backend/memory/types.ts +104 -0
  103. package/apps/server/src/backend/opencode/agentMockingbirdPlugin.test.ts +396 -0
  104. package/apps/server/src/backend/opencode/client.ts +98 -0
  105. package/apps/server/src/backend/opencode/models.ts +41 -0
  106. package/apps/server/src/backend/opencode/systemPrompt.test.ts +146 -0
  107. package/apps/server/src/backend/opencode/systemPrompt.ts +284 -0
  108. package/apps/server/src/backend/paths.ts +57 -0
  109. package/apps/server/src/backend/prompts/service.ts +100 -0
  110. package/apps/server/src/backend/queue/queue.test.ts +189 -0
  111. package/apps/server/src/backend/queue/service.ts +177 -0
  112. package/apps/server/src/backend/queue/types.ts +39 -0
  113. package/apps/server/src/backend/run/service.ts +576 -0
  114. package/apps/server/src/backend/run/storage.ts +47 -0
  115. package/apps/server/src/backend/run/types.ts +44 -0
  116. package/apps/server/src/backend/runtime/errors.ts +61 -0
  117. package/apps/server/src/backend/runtime/index.ts +72 -0
  118. package/apps/server/src/backend/runtime/memoryPromptDedup.test.ts +153 -0
  119. package/apps/server/src/backend/runtime/memoryPromptDedup.ts +76 -0
  120. package/apps/server/src/backend/runtime/opencodeRuntime/backgroundMethods.ts +765 -0
  121. package/apps/server/src/backend/runtime/opencodeRuntime/coreMethods.ts +705 -0
  122. package/apps/server/src/backend/runtime/opencodeRuntime/eventMethods.ts +503 -0
  123. package/apps/server/src/backend/runtime/opencodeRuntime/memoryMethods.ts +462 -0
  124. package/apps/server/src/backend/runtime/opencodeRuntime/promptMethods.ts +1167 -0
  125. package/apps/server/src/backend/runtime/opencodeRuntime/shared.ts +254 -0
  126. package/apps/server/src/backend/runtime/opencodeRuntime.test.ts +2899 -0
  127. package/apps/server/src/backend/runtime/opencodeRuntime.ts +135 -0
  128. package/apps/server/src/backend/runtime/sessionScope.ts +45 -0
  129. package/apps/server/src/backend/skills/service.ts +442 -0
  130. package/apps/server/src/backend/workspace/resolve.ts +27 -0
  131. package/apps/server/src/cli/agent-mockingbird.mjs +2522 -0
  132. package/apps/server/src/cli/agent-mockingbird.test.ts +68 -0
  133. package/apps/server/src/cli/runtime-assets.mjs +269 -0
  134. package/apps/server/src/cli/runtime-assets.test.ts +52 -0
  135. package/apps/server/src/cli/runtime-layout.mjs +75 -0
  136. package/apps/server/src/cli/standaloneBuild.test.ts +19 -0
  137. package/apps/server/src/cli/standaloneBuild.ts +19 -0
  138. package/apps/server/src/cli/standaloneCronBinary.test.ts +187 -0
  139. package/apps/server/src/index.ts +178 -0
  140. package/apps/server/tsconfig.json +12 -0
  141. package/backlog.md +5 -0
  142. package/bin/agent-mockingbird +2522 -0
  143. package/bin/runtime-layout.mjs +75 -0
  144. package/build-bin.ts +34 -0
  145. package/build-cli.mjs +37 -0
  146. package/build.ts +40 -0
  147. package/bun-env.d.ts +11 -0
  148. package/bun.lock +888 -0
  149. package/bunfig.toml +2 -0
  150. package/components.json +21 -0
  151. package/config.json +130 -0
  152. package/deploy/RELEASE_INSTALL.md +112 -0
  153. package/deploy/docker-compose.yml +42 -0
  154. package/deploy/systemd/README.md +46 -0
  155. package/deploy/systemd/agent-mockingbird.service +28 -0
  156. package/deploy/systemd/opencode.service +25 -0
  157. package/docs/legacy-config-ui-reference.md +51 -0
  158. package/docs/memory-e2e-trace-2026-03-04.md +63 -0
  159. package/docs/memory-ops.md +96 -0
  160. package/docs/memory-runtime-contract.md +42 -0
  161. package/docs/memory-tuning-remote-2026-03-04.md +59 -0
  162. package/docs/opencode-rebase-workflow-plan.md +614 -0
  163. package/docs/opencode-startup-sync-plan.md +94 -0
  164. package/docs/vendor-opencode.md +41 -0
  165. package/drizzle/0000_famous_turbo.sql +49 -0
  166. package/drizzle/0001_cron_memory_aux.sql +160 -0
  167. package/drizzle/0002_runtime_session_bindings.sql +28 -0
  168. package/drizzle/0003_background_runs.sql +27 -0
  169. package/drizzle/0004_memory_open_write.sql +63 -0
  170. package/drizzle/0005_signal_channel.sql +47 -0
  171. package/drizzle/0006_usage_event_dimensions.sql +7 -0
  172. package/drizzle/meta/0000_snapshot.json +341 -0
  173. package/drizzle/meta/_journal.json +55 -0
  174. package/drizzle.config.ts +14 -0
  175. package/eslint.config.mjs +77 -0
  176. package/knip.json +18 -0
  177. package/memory/2026-03-04.md +4 -0
  178. package/opencode.lock.json +16 -0
  179. package/package.json +67 -0
  180. package/packages/agent-mockingbird-installer/README.md +31 -0
  181. package/packages/agent-mockingbird-installer/bin/agent-mockingbird-installer.mjs +44 -0
  182. package/packages/agent-mockingbird-installer/opencode.lock.json +16 -0
  183. package/packages/agent-mockingbird-installer/package.json +23 -0
  184. package/packages/contracts/package.json +19 -0
  185. package/packages/contracts/src/agentTypes.ts +122 -0
  186. package/packages/contracts/src/cron.ts +146 -0
  187. package/packages/contracts/src/dashboard.ts +378 -0
  188. package/packages/contracts/src/index.ts +3 -0
  189. package/packages/contracts/tsconfig.json +4 -0
  190. package/patches/opencode/0001-Wafflebot-OpenCode-baseline.patch +2341 -0
  191. package/patches/opencode/0002-Fix-OpenCode-web-entry-and-settings-icons.patch +104 -0
  192. package/patches/opencode/0003-fix-app-remove-duplicate-sidebar-mount.patch +32 -0
  193. package/patches/opencode/0004-Add-heartbeat-settings-and-usage-nav.patch +506 -0
  194. package/patches/opencode/0005-Use-chart-icon-for-usage-nav.patch +38 -0
  195. package/patches/opencode/0006-Modernize-cron-settings.patch +399 -0
  196. package/patches/opencode/0007-Rename-waffle-namespaces-to-mockingbird.patch +1110 -0
  197. package/patches/opencode/0008-Remove-cron-contract-section.patch +178 -0
  198. package/patches/opencode/0009-Rework-cron-tab-as-operations-console.patch +414 -0
  199. package/patches/opencode/0010-Refine-heartbeat-settings-controls.patch +208 -0
  200. package/runtime-assets/opencode-config/opencode.jsonc +25 -0
  201. package/runtime-assets/opencode-config/package.json +5 -0
  202. package/runtime-assets/opencode-config/plugins/agent-mockingbird.ts +715 -0
  203. package/runtime-assets/workspace/.agents/skills/config-auditor/SKILL.md +25 -0
  204. package/runtime-assets/workspace/.agents/skills/config-editor/SKILL.md +24 -0
  205. package/runtime-assets/workspace/.agents/skills/cron-manager/SKILL.md +57 -0
  206. package/runtime-assets/workspace/.agents/skills/memory-ops/SKILL.md +120 -0
  207. package/runtime-assets/workspace/.agents/skills/runtime-diagnose/SKILL.md +25 -0
  208. package/runtime-assets/workspace/AGENTS.md +56 -0
  209. package/runtime-assets/workspace/MEMORY.md +4 -0
  210. package/scripts/build-release-bundle.sh +66 -0
  211. package/scripts/check-ship.ts +383 -0
  212. package/scripts/dev-opencode.sh +17 -0
  213. package/scripts/dev-stack-opencode.sh +15 -0
  214. package/scripts/dev-stack.sh +61 -0
  215. package/scripts/install-systemd.sh +87 -0
  216. package/scripts/memory-e2e.sh +76 -0
  217. package/scripts/memory-trace-e2e.sh +141 -0
  218. package/scripts/migrate-opencode-env.ts +108 -0
  219. package/scripts/onboard/bootstrap.sh +32 -0
  220. package/scripts/opencode-swap.ts +78 -0
  221. package/scripts/opencode-sync.ts +715 -0
  222. package/scripts/runtime-assets-sync.mjs +83 -0
  223. package/scripts/setup-git-hooks.ts +39 -0
  224. package/tsconfig.json +45 -0
  225. package/tui.json +98 -0
  226. package/turbo.json +36 -0
  227. package/vendor/OPENCODE_VENDOR.md +13 -0
@@ -0,0 +1,87 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+ import { z } from "zod";
3
+
4
+ function resolveApiBaseUrl() {
5
+ const explicit = process.env.AGENT_MOCKINGBIRD_CONFIG_API_BASE_URL?.trim();
6
+ if (explicit) return explicit.replace(/\/+$/, "");
7
+ const memoryAlias = process.env.AGENT_MOCKINGBIRD_MEMORY_API_BASE_URL?.trim();
8
+ if (memoryAlias) return memoryAlias.replace(/\/+$/, "");
9
+ const cronAlias = process.env.AGENT_MOCKINGBIRD_CRON_API_BASE_URL?.trim();
10
+ if (cronAlias) return cronAlias.replace(/\/+$/, "");
11
+ const port = process.env.AGENT_MOCKINGBIRD_PORT?.trim() || process.env.PORT?.trim() || "3001";
12
+ return `http://127.0.0.1:${port}`;
13
+ }
14
+
15
+ async function requestJson(pathname: string, init?: RequestInit) {
16
+ const response = await fetch(`${resolveApiBaseUrl()}${pathname}`, init);
17
+ const payload = (await response.json()) as Record<string, unknown>;
18
+ if (!response.ok) {
19
+ const error = typeof payload.error === "string" ? payload.error : `Request failed (${response.status})`;
20
+ throw new Error(error);
21
+ }
22
+ return payload;
23
+ }
24
+
25
+ const argsSchema = z.discriminatedUnion("action", [
26
+ z.object({ action: z.literal("get_config") }),
27
+ z.object({
28
+ action: z.literal("patch_config"),
29
+ patch: z.unknown(),
30
+ expectedHash: z.string().min(1),
31
+ runSmokeTest: z.boolean().optional(),
32
+ }),
33
+ z.object({
34
+ action: z.literal("replace_config"),
35
+ config: z.unknown(),
36
+ expectedHash: z.string().min(1),
37
+ runSmokeTest: z.boolean().optional(),
38
+ }),
39
+ ]);
40
+
41
+ export default tool({
42
+ description:
43
+ "Read or update Agent Mockingbird managed config through validated APIs with hash conflict detection and optional smoke tests.",
44
+ args: {
45
+ action: tool.schema.enum(["get_config", "patch_config", "replace_config"]),
46
+ patch: tool.schema.unknown().optional(),
47
+ config: tool.schema.unknown().optional(),
48
+ expectedHash: tool.schema.string().min(1).optional(),
49
+ runSmokeTest: tool.schema.boolean().optional(),
50
+ },
51
+ async execute(rawArgs: {
52
+ action: "get_config" | "patch_config" | "replace_config";
53
+ patch?: unknown;
54
+ config?: unknown;
55
+ expectedHash?: string;
56
+ runSmokeTest?: boolean;
57
+ }) {
58
+ const args = argsSchema.parse(rawArgs);
59
+
60
+ if (args.action === "get_config") {
61
+ const payload = await requestJson("/api/waffle/runtime/config");
62
+ return JSON.stringify({ ok: true, ...payload });
63
+ }
64
+
65
+ if (args.action === "patch_config") {
66
+ const payload = await requestJson("/api/waffle/runtime/config", {
67
+ method: "PATCH",
68
+ headers: { "Content-Type": "application/json" },
69
+ body: JSON.stringify({
70
+ patch: args.patch,
71
+ expectedHash: args.expectedHash,
72
+ }),
73
+ });
74
+ return JSON.stringify({ ok: true, ...payload });
75
+ }
76
+
77
+ const payload = await requestJson("/api/waffle/runtime/config/replace", {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/json" },
80
+ body: JSON.stringify({
81
+ config: args.config,
82
+ expectedHash: args.expectedHash,
83
+ }),
84
+ });
85
+ return JSON.stringify({ ok: true, ...payload });
86
+ },
87
+ });
@@ -0,0 +1,145 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+ import { z } from "zod";
3
+
4
+ function resolveApiBaseUrl() {
5
+ const explicit = process.env.AGENT_MOCKINGBIRD_CRON_API_BASE_URL?.trim();
6
+ if (explicit) return explicit.replace(/\/+$/, "");
7
+ const memoryAlias = process.env.AGENT_MOCKINGBIRD_MEMORY_API_BASE_URL?.trim();
8
+ if (memoryAlias) return memoryAlias.replace(/\/+$/, "");
9
+ const port = process.env.AGENT_MOCKINGBIRD_PORT?.trim() || process.env.PORT?.trim() || "3001";
10
+ return `http://127.0.0.1:${port}`;
11
+ }
12
+
13
+ async function postJson(pathname: string, body: unknown) {
14
+ const response = await fetch(`${resolveApiBaseUrl()}${pathname}`, {
15
+ method: "POST",
16
+ headers: { "Content-Type": "application/json" },
17
+ body: JSON.stringify(body),
18
+ });
19
+ const payload = (await response.json()) as Record<string, unknown>;
20
+ if (!response.ok) {
21
+ const error = typeof payload.error === "string" ? payload.error : `Request failed (${response.status})`;
22
+ throw new Error(error);
23
+ }
24
+ return payload;
25
+ }
26
+
27
+ const scheduleKindSchema = z.enum(["at", "every", "cron"]);
28
+ const runModeSchema = z.enum(["background", "conditional_agent", "agent"]);
29
+ const payloadSchema = z.record(z.string(), z.unknown());
30
+
31
+ const jobCreateSchema = z.object({
32
+ id: z.string().min(1).optional(),
33
+ name: z.string().min(1),
34
+ enabled: z.boolean().optional(),
35
+ scheduleKind: scheduleKindSchema,
36
+ scheduleExpr: z.string().min(1).nullable().optional(),
37
+ everyMs: z.number().int().positive().nullable().optional(),
38
+ atIso: z.string().min(1).nullable().optional(),
39
+ timezone: z.string().min(1).nullable().optional(),
40
+ runMode: runModeSchema,
41
+ handlerKey: z.string().min(1).nullable().optional(),
42
+ conditionModulePath: z.string().min(1).nullable().optional(),
43
+ conditionDescription: z.string().min(1).nullable().optional(),
44
+ agentPromptTemplate: z.string().min(1).nullable().optional(),
45
+ agentModelOverride: z.string().min(1).nullable().optional(),
46
+ maxAttempts: z.number().int().positive().optional(),
47
+ retryBackoffMs: z.number().int().positive().optional(),
48
+ payload: payloadSchema.optional(),
49
+ });
50
+
51
+ const jobPatchSchema = z.object({
52
+ name: z.string().min(1).optional(),
53
+ enabled: z.boolean().optional(),
54
+ scheduleKind: scheduleKindSchema.optional(),
55
+ scheduleExpr: z.string().min(1).nullable().optional(),
56
+ everyMs: z.number().int().positive().nullable().optional(),
57
+ atIso: z.string().min(1).nullable().optional(),
58
+ timezone: z.string().min(1).nullable().optional(),
59
+ runMode: runModeSchema.optional(),
60
+ handlerKey: z.string().min(1).nullable().optional(),
61
+ conditionModulePath: z.string().min(1).nullable().optional(),
62
+ conditionDescription: z.string().min(1).nullable().optional(),
63
+ agentPromptTemplate: z.string().min(1).nullable().optional(),
64
+ agentModelOverride: z.string().min(1).nullable().optional(),
65
+ maxAttempts: z.number().int().positive().optional(),
66
+ retryBackoffMs: z.number().int().positive().optional(),
67
+ payload: payloadSchema.optional(),
68
+ });
69
+
70
+ const argsSchema = z.discriminatedUnion("action", [
71
+ z.object({ action: z.literal("list_jobs") }),
72
+ z.object({ action: z.literal("list_handlers") }),
73
+ z.object({ action: z.literal("health") }),
74
+ z.object({ action: z.literal("get_job"), jobId: z.string().min(1) }),
75
+ z.object({ action: z.literal("create_job"), job: jobCreateSchema }),
76
+ z.object({ action: z.literal("upsert_job"), job: jobCreateSchema }),
77
+ z.object({ action: z.literal("update_job"), jobId: z.string().min(1), patch: jobPatchSchema }),
78
+ z.object({ action: z.literal("enable_job"), jobId: z.string().min(1) }),
79
+ z.object({ action: z.literal("disable_job"), jobId: z.string().min(1) }),
80
+ z.object({ action: z.literal("describe_contract") }),
81
+ z.object({ action: z.literal("delete_job"), jobId: z.string().min(1) }),
82
+ z.object({ action: z.literal("run_job_now"), jobId: z.string().min(1) }),
83
+ z.object({
84
+ action: z.literal("list_instances"),
85
+ jobId: z.string().min(1).optional(),
86
+ limit: z.number().int().positive().optional(),
87
+ }),
88
+ z.object({ action: z.literal("list_steps"), instanceId: z.string().min(1) }),
89
+ ]);
90
+
91
+ export default tool({
92
+ description: "Manage Agent Mockingbird cron jobs (list/create/update/run/delete/inspect).",
93
+ args: {
94
+ action: tool.schema.enum([
95
+ "list_jobs",
96
+ "list_handlers",
97
+ "health",
98
+ "get_job",
99
+ "create_job",
100
+ "upsert_job",
101
+ "update_job",
102
+ "enable_job",
103
+ "disable_job",
104
+ "describe_contract",
105
+ "delete_job",
106
+ "run_job_now",
107
+ "list_instances",
108
+ "list_steps",
109
+ ]),
110
+ jobId: tool.schema.string().optional(),
111
+ instanceId: tool.schema.string().optional(),
112
+ limit: tool.schema.number().int().positive().optional(),
113
+ job: tool.schema.unknown().optional(),
114
+ patch: tool.schema.unknown().optional(),
115
+ },
116
+ async execute(rawArgs: {
117
+ action:
118
+ | "list_jobs"
119
+ | "list_handlers"
120
+ | "health"
121
+ | "get_job"
122
+ | "create_job"
123
+ | "upsert_job"
124
+ | "update_job"
125
+ | "enable_job"
126
+ | "disable_job"
127
+ | "describe_contract"
128
+ | "delete_job"
129
+ | "run_job_now"
130
+ | "list_instances"
131
+ | "list_steps";
132
+ jobId?: string;
133
+ instanceId?: string;
134
+ limit?: number;
135
+ job?: unknown;
136
+ patch?: unknown;
137
+ }) {
138
+ const args = argsSchema.parse(rawArgs);
139
+ const payload = await postJson("/api/waffle/cron/manage", args);
140
+ return JSON.stringify({
141
+ ok: true,
142
+ ...payload,
143
+ });
144
+ },
145
+ });
@@ -0,0 +1,43 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+
3
+ function resolveApiBaseUrl() {
4
+ const explicit = process.env.AGENT_MOCKINGBIRD_MEMORY_API_BASE_URL?.trim();
5
+ if (explicit) return explicit.replace(/\/+$/, "");
6
+ const port = process.env.AGENT_MOCKINGBIRD_PORT?.trim() || process.env.PORT?.trim() || "3001";
7
+ return `http://127.0.0.1:${port}`;
8
+ }
9
+
10
+ async function postJson(pathname: string, body: unknown) {
11
+ const response = await fetch(`${resolveApiBaseUrl()}${pathname}`, {
12
+ method: "POST",
13
+ headers: { "Content-Type": "application/json" },
14
+ body: JSON.stringify(body),
15
+ });
16
+ const payload = (await response.json()) as Record<string, unknown>;
17
+ if (!response.ok) {
18
+ const error = typeof payload.error === "string" ? payload.error : `Request failed (${response.status})`;
19
+ throw new Error(error);
20
+ }
21
+ return payload;
22
+ }
23
+
24
+ export default tool({
25
+ description: "Read a safe slice of canonical markdown memory files by path and line window.",
26
+ args: {
27
+ path: tool.schema.string().min(1).describe("Memory path such as MEMORY.md or memory/2026-02-17.md"),
28
+ from: tool.schema.number().int().min(1).optional().describe("Start line number (1-based)"),
29
+ lines: tool.schema.number().int().min(1).max(400).optional().describe("Number of lines to return"),
30
+ },
31
+ async execute(args: { path: string; from?: number; lines?: number }) {
32
+ const payload = await postJson("/api/waffle/memory/read", {
33
+ path: args.path,
34
+ from: args.from,
35
+ lines: args.lines,
36
+ });
37
+ return JSON.stringify({
38
+ ok: true,
39
+ path: payload.path,
40
+ text: payload.text,
41
+ });
42
+ },
43
+ });
@@ -0,0 +1,53 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+
3
+ function resolveApiBaseUrl() {
4
+ const explicit = process.env.AGENT_MOCKINGBIRD_MEMORY_API_BASE_URL?.trim();
5
+ if (explicit) return explicit.replace(/\/+$/, "");
6
+ const port = process.env.AGENT_MOCKINGBIRD_PORT?.trim() || process.env.PORT?.trim() || "3001";
7
+ return `http://127.0.0.1:${port}`;
8
+ }
9
+
10
+ async function postJson(pathname: string, body: unknown) {
11
+ const response = await fetch(`${resolveApiBaseUrl()}${pathname}`, {
12
+ method: "POST",
13
+ headers: { "Content-Type": "application/json" },
14
+ body: JSON.stringify(body),
15
+ });
16
+ const payload = (await response.json()) as Record<string, unknown>;
17
+ if (!response.ok && response.status !== 422) {
18
+ const error = typeof payload.error === "string" ? payload.error : `Request failed (${response.status})`;
19
+ throw new Error(error);
20
+ }
21
+ return { ok: response.ok, status: response.status, payload };
22
+ }
23
+
24
+ export default tool({
25
+ description: "Persist a memory note so it can be retrieved later.",
26
+ args: {
27
+ content: tool.schema.string().min(1),
28
+ confidence: tool.schema.number().min(0).max(1).optional(),
29
+ source: tool.schema.enum(["assistant", "user", "system"]).optional(),
30
+ entities: tool.schema.array(tool.schema.string()).optional(),
31
+ supersedes: tool.schema.array(tool.schema.string()).optional(),
32
+ topic: tool.schema.string().optional(),
33
+ },
34
+ async execute(args: {
35
+ content: string;
36
+ confidence?: number;
37
+ source?: "assistant" | "user" | "system";
38
+ entities?: string[];
39
+ supersedes?: string[];
40
+ topic?: string;
41
+ }) {
42
+ const response = await postJson("/api/waffle/memory/remember", {
43
+ ...args,
44
+ source: args.source ?? "assistant",
45
+ });
46
+
47
+ return JSON.stringify({
48
+ ok: response.ok,
49
+ status: response.status,
50
+ result: response.payload,
51
+ });
52
+ },
53
+ });
@@ -0,0 +1,48 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+
3
+ function resolveApiBaseUrl() {
4
+ const explicit = process.env.AGENT_MOCKINGBIRD_MEMORY_API_BASE_URL?.trim();
5
+ if (explicit) return explicit.replace(/\/+$/, "");
6
+ const port = process.env.AGENT_MOCKINGBIRD_PORT?.trim() || process.env.PORT?.trim() || "3001";
7
+ return `http://127.0.0.1:${port}`;
8
+ }
9
+
10
+ async function postJson(pathname: string, body: unknown) {
11
+ const response = await fetch(`${resolveApiBaseUrl()}${pathname}`, {
12
+ method: "POST",
13
+ headers: { "Content-Type": "application/json" },
14
+ body: JSON.stringify(body),
15
+ });
16
+ const payload = (await response.json()) as Record<string, unknown>;
17
+ if (!response.ok) {
18
+ const error = typeof payload.error === "string" ? payload.error : `Request failed (${response.status})`;
19
+ throw new Error(error);
20
+ }
21
+ return payload;
22
+ }
23
+
24
+ export default tool({
25
+ description: "Search memory for relevant prior context.",
26
+ args: {
27
+ query: tool.schema.string().min(1).describe("Natural language memory query"),
28
+ maxResults: tool.schema.number().int().min(1).max(20).optional(),
29
+ minScore: tool.schema.number().min(0).max(1).optional(),
30
+ debug: tool.schema.boolean().optional().describe("Include retrieval debug details."),
31
+ },
32
+ async execute(args: { query: string; maxResults?: number; minScore?: number; debug?: boolean }) {
33
+ const payload = await postJson("/api/waffle/memory/retrieve", {
34
+ query: args.query,
35
+ maxResults: args.maxResults,
36
+ minScore: args.minScore,
37
+ debug: args.debug,
38
+ });
39
+ const results = Array.isArray(payload.results) ? payload.results : [];
40
+ return JSON.stringify({
41
+ ok: true,
42
+ query: args.query,
43
+ count: results.length,
44
+ results,
45
+ debug: args.debug ? payload.debug : undefined,
46
+ });
47
+ },
48
+ });
package/AGENTS.md ADDED
@@ -0,0 +1,126 @@
1
+ THIS IS A NON-PRODUCTION APP Do not assume we need to make migrations or support old systems if we're doing large scale refactors. Assume we can make breaking changes as long as this is here, as there are no users other than me, the author, testing it. And all my tests get wiped when done. If we are making a newer better system, no need to support the old one at all.
2
+
3
+
4
+ Default to using Bun instead of Node.js.
5
+
6
+ - Use `bun <file>` instead of `node <file>` or `ts-node <file>`
7
+ - Use `bun test` instead of `jest` or `vitest`
8
+ - Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
9
+ - Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
10
+ - Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
11
+ - Use `bunx <package> <command>` instead of `npx <package> <command>`
12
+ - Bun automatically loads .env, so don't use dotenv.
13
+
14
+ ## APIs
15
+
16
+ - `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
17
+ - `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
18
+ - `Bun.redis` for Redis. Don't use `ioredis`.
19
+ - `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
20
+ - `WebSocket` is built-in. Don't use `ws`.
21
+ - Prefer `Bun.file` over `node:fs`'s readFile/writeFile
22
+ - Bun.$`ls` instead of execa.
23
+
24
+ ## Testing
25
+
26
+ Use `bun test` to run tests.
27
+
28
+ ```ts#index.test.ts
29
+ import { test, expect } from "bun:test";
30
+
31
+ test("hello world", () => {
32
+ expect(1).toBe(1);
33
+ });
34
+ ```
35
+
36
+ ## Frontend
37
+
38
+ Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
39
+
40
+ Server:
41
+
42
+ ```ts#index.ts
43
+ import index from "./index.html"
44
+
45
+ Bun.serve({
46
+ routes: {
47
+ "/": index,
48
+ "/api/users/:id": {
49
+ GET: (req) => {
50
+ return new Response(JSON.stringify({ id: req.params.id }));
51
+ },
52
+ },
53
+ },
54
+ // optional websocket support
55
+ websocket: {
56
+ open: (ws) => {
57
+ ws.send("Hello, world!");
58
+ },
59
+ message: (ws, message) => {
60
+ ws.send(message);
61
+ },
62
+ close: (ws) => {
63
+ // handle close
64
+ }
65
+ },
66
+ development: {
67
+ hmr: true,
68
+ console: true,
69
+ }
70
+ })
71
+ ```
72
+
73
+ HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
74
+
75
+ ```html#index.html
76
+ <html>
77
+ <body>
78
+ <h1>Hello, world!</h1>
79
+ <script type="module" src="./frontend.tsx"></script>
80
+ </body>
81
+ </html>
82
+ ```
83
+
84
+ With the following `frontend.tsx`:
85
+
86
+ ```tsx#frontend.tsx
87
+ import React from "react";
88
+ import { createRoot } from "react-dom/client";
89
+
90
+ // import .css files directly and it works
91
+ import './index.css';
92
+
93
+ const root = createRoot(document.body);
94
+
95
+ export default function Frontend() {
96
+ return <h1>Hello, world!</h1>;
97
+ }
98
+
99
+ root.render(<Frontend />);
100
+ ```
101
+
102
+ Then, run index.ts
103
+
104
+ ```sh
105
+ bun --hot ./index.ts
106
+ ```
107
+
108
+ For more information, read the Bun API docs in `node_modules/bun-types/docs/**.mdx`.
109
+
110
+ ## Temporary Streamdown Integration Rule
111
+
112
+ For the mobile Streamdown integration effort:
113
+ - Treat `/var/home/matt/Documents/random-vibecoded-stuff/streamdown` as the source of truth for Streamdown library changes.
114
+ - Do not patch Streamdown library internals in this repo when the same change can be made in the Streamdown fork.
115
+ - Keep changes in this repo limited to integration wiring (dependencies, config, app usage), while implementing library fixes/features in the Streamdown fork for upstream publishing.
116
+ - If a Streamdown-side change is required, make it in the fork first, then consume it here via local dependency links.
117
+
118
+ ## OpenCode Workflow
119
+
120
+ - Do not edit `cleanroom/opencode` directly.
121
+ - If a task needs shipped OpenCode source changes, run `bun run opencode:sync --rebuild-only` first.
122
+ - Make OpenCode edits only in `vendor/opencode`.
123
+ - Commit OpenCode changes in the `vendor/opencode` worktree before exporting them.
124
+ - Run `bun run opencode:sync --export-patches` after committing OpenCode changes.
125
+ - Use `bun run opencode:sync --ref <tag>` for upstream bumps.
126
+ - If `vendor/opencode` is dirty, do not run `--ref` or `--export-patches`.
package/MEMORY.md ADDED
@@ -0,0 +1,2 @@
1
+ # Memory
2
+