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,383 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
|
|
7
|
+
type CommandResult = {
|
|
8
|
+
status: number;
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
combined: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type SyncStatus = {
|
|
15
|
+
cleanroom: {
|
|
16
|
+
exists: boolean;
|
|
17
|
+
pristine: boolean | null;
|
|
18
|
+
matchesLock: boolean | null;
|
|
19
|
+
path: string;
|
|
20
|
+
};
|
|
21
|
+
vendor: {
|
|
22
|
+
exists: boolean;
|
|
23
|
+
state: "missing" | "clean" | "dirty" | "conflicted" | "invalid";
|
|
24
|
+
path: string;
|
|
25
|
+
};
|
|
26
|
+
patches: {
|
|
27
|
+
matchesBranch: boolean | null;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type Diagnostic = {
|
|
32
|
+
key: string;
|
|
33
|
+
line: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const repoRoot = path.resolve(import.meta.dir, "..");
|
|
37
|
+
const cleanroomRoot = path.join(repoRoot, "cleanroom", "opencode");
|
|
38
|
+
const vendorRoot = path.join(repoRoot, "vendor", "opencode");
|
|
39
|
+
const trackedArtifactPaths = ["bin/agent-mockingbird"];
|
|
40
|
+
|
|
41
|
+
main();
|
|
42
|
+
|
|
43
|
+
function main() {
|
|
44
|
+
ensureOpencodeWorktree();
|
|
45
|
+
const initialStatus = readSyncStatus();
|
|
46
|
+
if (!initialStatus) {
|
|
47
|
+
fail("Unable to read OpenCode sync status after worktree setup.");
|
|
48
|
+
}
|
|
49
|
+
assertShipState(initialStatus);
|
|
50
|
+
|
|
51
|
+
runStep("Build CLI", ["bun", "run", "build:cli"]);
|
|
52
|
+
assertTrackedArtifactsSynced(["bin/agent-mockingbird"]);
|
|
53
|
+
|
|
54
|
+
runStep("Lint", ["bun", "run", "lint"]);
|
|
55
|
+
runStep("Typecheck", ["bun", "run", "typecheck"]);
|
|
56
|
+
|
|
57
|
+
runStep("OpenCode Patch Check", ["bun", "run", "opencode:sync", "--check"]);
|
|
58
|
+
runFilteredOpencodeTypecheck();
|
|
59
|
+
|
|
60
|
+
runStep("Build", ["bun", "run", "build"]);
|
|
61
|
+
assertDistAppBuilt();
|
|
62
|
+
assertTrackedArtifactsSynced(trackedArtifactPaths);
|
|
63
|
+
|
|
64
|
+
runStep("Build Standalone Runtime", ["bun", "run", "build:bin"]);
|
|
65
|
+
assertTrackedArtifactsSynced(["bin/agent-mockingbird"]);
|
|
66
|
+
|
|
67
|
+
console.log("\nShip check passed.");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function ensureOpencodeWorktree() {
|
|
71
|
+
const status = readSyncStatus({ allowFailure: true });
|
|
72
|
+
if (status && status.vendor.exists) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log("\n== Materialize OpenCode Worktree ==");
|
|
77
|
+
runCommand(["bun", "run", "opencode:sync", "--rebuild-only"]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function assertShipState(status: SyncStatus) {
|
|
81
|
+
const problems: string[] = [];
|
|
82
|
+
|
|
83
|
+
if (!status.cleanroom.exists) {
|
|
84
|
+
problems.push("cleanroom/opencode is missing");
|
|
85
|
+
}
|
|
86
|
+
if (status.cleanroom.pristine !== true) {
|
|
87
|
+
problems.push("cleanroom/opencode is not pristine");
|
|
88
|
+
}
|
|
89
|
+
if (status.cleanroom.matchesLock !== true) {
|
|
90
|
+
problems.push("cleanroom/opencode does not match opencode.lock.json");
|
|
91
|
+
}
|
|
92
|
+
if (!status.vendor.exists) {
|
|
93
|
+
problems.push("vendor/opencode is missing");
|
|
94
|
+
}
|
|
95
|
+
if (status.vendor.state !== "clean") {
|
|
96
|
+
problems.push(`vendor/opencode is ${status.vendor.state}`);
|
|
97
|
+
}
|
|
98
|
+
if (status.patches.matchesBranch !== true) {
|
|
99
|
+
problems.push("patches/opencode does not match the vendor patch branch");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (problems.length === 0) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const detail = problems.map((item) => `- ${item}`).join("\n");
|
|
107
|
+
fail(`OpenCode ship state is not clean:\n${detail}\n\nCommit/export vendor changes or rebuild the worktree before shipping.`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function runFilteredOpencodeTypecheck() {
|
|
111
|
+
console.log("\n== OpenCode Dependency Install ==");
|
|
112
|
+
runCommand(["bun", "install", "--cwd", cleanroomRoot, "--frozen-lockfile"], {
|
|
113
|
+
quietLabel: "cleanroom/opencode",
|
|
114
|
+
env: bunInstallEnv(),
|
|
115
|
+
});
|
|
116
|
+
runCommand(["bun", "install", "--cwd", vendorRoot, "--frozen-lockfile"], {
|
|
117
|
+
quietLabel: "vendor/opencode",
|
|
118
|
+
env: bunInstallEnv(),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
console.log("\n== OpenCode Full Typecheck ==");
|
|
122
|
+
const cleanroomResult = runCommand(
|
|
123
|
+
["bun", "run", "--cwd", cleanroomRoot, "typecheck"],
|
|
124
|
+
{ allowFailure: true, quietLabel: "cleanroom/opencode" },
|
|
125
|
+
);
|
|
126
|
+
const vendorResult = runCommand(
|
|
127
|
+
["bun", "run", "--cwd", vendorRoot, "typecheck"],
|
|
128
|
+
{ allowFailure: true, quietLabel: "vendor/opencode" },
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (cleanroomResult.status === 0 && vendorResult.status === 0) {
|
|
132
|
+
console.log("OpenCode cleanroom and vendor workspaces both typecheck cleanly.");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (cleanroomResult.status === 0 && vendorResult.status !== 0) {
|
|
137
|
+
fail(
|
|
138
|
+
"Patched OpenCode workspace typecheck failed while cleanroom passed.\n\nVendor output:\n" +
|
|
139
|
+
indentBlock(vendorResult.combined || "<no output>"),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const cleanroomDiagnostics = collectDiagnostics(cleanroomResult.combined, cleanroomRoot);
|
|
144
|
+
const vendorDiagnostics = collectDiagnostics(vendorResult.combined, vendorRoot);
|
|
145
|
+
const cleanroomKeys = new Set(cleanroomDiagnostics.map((item) => item.key));
|
|
146
|
+
const vendorOnlyDiagnostics = vendorDiagnostics.filter((item) => !cleanroomKeys.has(item.key));
|
|
147
|
+
|
|
148
|
+
if (vendorOnlyDiagnostics.length > 0) {
|
|
149
|
+
const detail = vendorOnlyDiagnostics.map((item) => `- ${item.line}`).join("\n");
|
|
150
|
+
fail(`Patched OpenCode introduced new typecheck diagnostics:\n${detail}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (vendorDiagnostics.length === 0 && cleanroomDiagnostics.length === 0) {
|
|
154
|
+
const cleanroomComparable = normalizeComparableOutput(cleanroomResult.combined, cleanroomRoot);
|
|
155
|
+
const vendorComparable = normalizeComparableOutput(vendorResult.combined, vendorRoot);
|
|
156
|
+
if (cleanroomComparable !== vendorComparable) {
|
|
157
|
+
fail(
|
|
158
|
+
"OpenCode workspace typecheck failed in both cleanroom and vendor, but the failures do not normalize to the same output.\n\nVendor output:\n" +
|
|
159
|
+
indentBlock(vendorResult.combined || "<no output>"),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (vendorResult.status !== 0) {
|
|
165
|
+
const baselineCount = vendorDiagnostics.length || countComparableLines(normalizeComparableOutput(vendorResult.combined, vendorRoot));
|
|
166
|
+
console.log(`Ignoring ${baselineCount} cleanroom-matching OpenCode typecheck issue(s).`);
|
|
167
|
+
if (vendorDiagnostics.length > 0) {
|
|
168
|
+
console.log("Ignored baseline diagnostics:");
|
|
169
|
+
for (const diagnostic of vendorDiagnostics) {
|
|
170
|
+
console.log(`- ${diagnostic.line}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function collectDiagnostics(output: string, workspaceRoot: string) {
|
|
177
|
+
const diagnostics = new Map<string, Diagnostic>();
|
|
178
|
+
const lines = stripAnsi(output).split(/\r?\n/);
|
|
179
|
+
|
|
180
|
+
for (const rawLine of lines) {
|
|
181
|
+
const line = rawLine.trimEnd();
|
|
182
|
+
const match = line.match(
|
|
183
|
+
/^(?<task>.+?:typecheck:\s+)?(?<file>.+?)\((?<line>\d+),(?<column>\d+)\): error TS(?<code>\d+): (?<message>.+)$/,
|
|
184
|
+
);
|
|
185
|
+
if (!match?.groups) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const file = normalizePath(match.groups.file, workspaceRoot);
|
|
190
|
+
const row = match.groups.line;
|
|
191
|
+
const column = match.groups.column;
|
|
192
|
+
const code = `TS${match.groups.code}`;
|
|
193
|
+
const message = match.groups.message.trim();
|
|
194
|
+
const key = [file, row, column, code, message].join("|");
|
|
195
|
+
diagnostics.set(key, { key, line: `${file}(${row},${column}): error ${code}: ${message}` });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return [...diagnostics.values()];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function normalizeComparableOutput(output: string, workspaceRoot: string) {
|
|
202
|
+
const lines = stripAnsi(output)
|
|
203
|
+
.split(/\r?\n/)
|
|
204
|
+
.map((line) => line.trimEnd())
|
|
205
|
+
.filter(Boolean)
|
|
206
|
+
.filter((line) => !isNoiseLine(line))
|
|
207
|
+
.map((line) => normalizeRoot(line, workspaceRoot));
|
|
208
|
+
return lines.join("\n");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function countComparableLines(output: string) {
|
|
212
|
+
if (!output) {
|
|
213
|
+
return 0;
|
|
214
|
+
}
|
|
215
|
+
return output.split("\n").filter(Boolean).length;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function isNoiseLine(line: string) {
|
|
219
|
+
return (
|
|
220
|
+
line === "$ bun turbo typecheck" ||
|
|
221
|
+
line.startsWith("• turbo ") ||
|
|
222
|
+
line.startsWith("• Packages in scope:") ||
|
|
223
|
+
line.startsWith("• Running typecheck in ") ||
|
|
224
|
+
line.startsWith("• Remote caching ") ||
|
|
225
|
+
line.startsWith("Tasks:") ||
|
|
226
|
+
line.startsWith("Cached:") ||
|
|
227
|
+
line.startsWith("Time:")
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function normalizePath(filePath: string, workspaceRoot: string) {
|
|
232
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
233
|
+
if (path.isAbsolute(normalized)) {
|
|
234
|
+
return normalizeRoot(normalized, workspaceRoot);
|
|
235
|
+
}
|
|
236
|
+
return normalized.replace(/^\.\//, "");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function normalizeRoot(value: string, workspaceRoot: string) {
|
|
240
|
+
const normalizedRoot = workspaceRoot.replaceAll("\\", "/");
|
|
241
|
+
return value.replaceAll(normalizedRoot, "<workspace>").replaceAll(repoRoot.replaceAll("\\", "/"), "<repo>");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function assertDistAppBuilt() {
|
|
245
|
+
const indexPath = path.join(repoRoot, "dist", "app", "index.html");
|
|
246
|
+
const assetsPath = path.join(repoRoot, "dist", "app", "assets");
|
|
247
|
+
|
|
248
|
+
if (!existsSync(indexPath)) {
|
|
249
|
+
fail("Missing dist/app/index.html after build.");
|
|
250
|
+
}
|
|
251
|
+
if (!existsSync(assetsPath) || !directoryHasFiles(assetsPath)) {
|
|
252
|
+
fail("Missing built OpenCode app assets in dist/app/assets after build.");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function directoryHasFiles(targetPath: string): boolean {
|
|
257
|
+
for (const entry of readdirSync(targetPath)) {
|
|
258
|
+
const entryPath = path.join(targetPath, entry);
|
|
259
|
+
const stats = statSync(entryPath);
|
|
260
|
+
if (stats.isFile()) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
if (stats.isDirectory() && directoryHasFiles(entryPath)) {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function assertTrackedArtifactsSynced(pathsToCheck: string[]) {
|
|
271
|
+
const result = runCommand(["git", "diff", "--name-only", "--", ...pathsToCheck], { allowFailure: true, printCommand: false });
|
|
272
|
+
const changed = result.stdout
|
|
273
|
+
.split(/\r?\n/)
|
|
274
|
+
.map((line) => line.trim())
|
|
275
|
+
.filter(Boolean);
|
|
276
|
+
if (changed.length === 0) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const detail = changed.map((item) => `- ${item}`).join("\n");
|
|
281
|
+
fail(`Generated artifacts are out of sync:\n${detail}\n\nRebuild and commit the generated outputs before shipping.`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function readSyncStatus(options?: { allowFailure?: boolean }): SyncStatus | null {
|
|
285
|
+
const result = runCommand(
|
|
286
|
+
["bun", "run", "opencode:sync", "--status", "--json"],
|
|
287
|
+
{ allowFailure: options?.allowFailure ?? false, printCommand: false, suppressOutput: true },
|
|
288
|
+
);
|
|
289
|
+
if (result.status !== 0) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
return JSON.parse(result.stdout) as SyncStatus;
|
|
295
|
+
} catch (error) {
|
|
296
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
297
|
+
fail(`Failed to parse opencode sync status JSON: ${message}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function runStep(label: string, command: string[]) {
|
|
302
|
+
console.log(`\n== ${label} ==`);
|
|
303
|
+
runCommand(command);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function runCommand(
|
|
307
|
+
command: string[],
|
|
308
|
+
options: {
|
|
309
|
+
allowFailure?: boolean;
|
|
310
|
+
cwd?: string;
|
|
311
|
+
printCommand?: boolean;
|
|
312
|
+
quietLabel?: string;
|
|
313
|
+
suppressOutput?: boolean;
|
|
314
|
+
env?: NodeJS.ProcessEnv;
|
|
315
|
+
} = {},
|
|
316
|
+
): CommandResult {
|
|
317
|
+
const cwd = options.cwd ?? repoRoot;
|
|
318
|
+
if (options.printCommand !== false) {
|
|
319
|
+
console.log(`$ ${command.join(" ")}`);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const result = spawnSync(command[0], command.slice(1), {
|
|
323
|
+
cwd,
|
|
324
|
+
encoding: "utf8",
|
|
325
|
+
env: options.env ?? process.env,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const stdout = result.stdout || "";
|
|
329
|
+
const stderr = result.stderr || "";
|
|
330
|
+
const combined = [stdout, stderr].filter(Boolean).join(stdout && stderr ? "\n" : "");
|
|
331
|
+
|
|
332
|
+
if (options.suppressOutput) {
|
|
333
|
+
// Intentionally silent.
|
|
334
|
+
} else if (options.quietLabel) {
|
|
335
|
+
const summary = result.status === 0 ? "passed" : `failed (${result.status ?? "unknown"})`;
|
|
336
|
+
console.log(`${options.quietLabel}: ${summary}`);
|
|
337
|
+
} else {
|
|
338
|
+
if (stdout) {
|
|
339
|
+
process.stdout.write(stdout);
|
|
340
|
+
}
|
|
341
|
+
if (stderr) {
|
|
342
|
+
process.stderr.write(stderr);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if ((result.status ?? 0) !== 0 && !options.allowFailure) {
|
|
347
|
+
fail(
|
|
348
|
+
`Command failed: ${command.join(" ")}\n\n${combined ? indentBlock(combined) : " <no output>"}`,
|
|
349
|
+
result.status ?? 1,
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return {
|
|
354
|
+
status: result.status ?? 0,
|
|
355
|
+
stdout,
|
|
356
|
+
stderr,
|
|
357
|
+
combined,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function indentBlock(value: string) {
|
|
362
|
+
return value
|
|
363
|
+
.split(/\r?\n/)
|
|
364
|
+
.map((line) => ` ${line}`)
|
|
365
|
+
.join("\n");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function stripAnsi(value: string) {
|
|
369
|
+
return value.replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g, "");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function bunInstallEnv() {
|
|
373
|
+
return {
|
|
374
|
+
...process.env,
|
|
375
|
+
GITHUB_SERVER_URL: "https://github.com",
|
|
376
|
+
GITHUB_API_URL: "https://api.github.com",
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function fail(message: string, code = 1): never {
|
|
381
|
+
console.error(`\n${message}`);
|
|
382
|
+
process.exit(code);
|
|
383
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
WORKSPACE_DIR="${OPENCODE_WORKSPACE_DIR:-${ROOT_DIR}/apps/server/data/workspace}"
|
|
6
|
+
OPENCODE_HOST="${OPENCODE_HOST:-127.0.0.1}"
|
|
7
|
+
OPENCODE_PORT="${OPENCODE_PORT:-4096}"
|
|
8
|
+
|
|
9
|
+
mkdir -p "${WORKSPACE_DIR}"
|
|
10
|
+
cd "${WORKSPACE_DIR}"
|
|
11
|
+
|
|
12
|
+
exec bun run "${ROOT_DIR}/vendor/opencode/packages/opencode/src/index.ts" \
|
|
13
|
+
serve \
|
|
14
|
+
--hostname "${OPENCODE_HOST}" \
|
|
15
|
+
--port "${OPENCODE_PORT}" \
|
|
16
|
+
--print-logs \
|
|
17
|
+
--log-level INFO
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
OPENCODE_HOST="${OPENCODE_HOST:-127.0.0.1}"
|
|
6
|
+
OPENCODE_PORT="${OPENCODE_PORT:-4096}"
|
|
7
|
+
OPENCODE_HEALTH_URL="http://${OPENCODE_HOST}:${OPENCODE_PORT}/global/health"
|
|
8
|
+
STARTUP_TIMEOUT_SECONDS="${OPENCODE_STARTUP_TIMEOUT_SECONDS:-30}"
|
|
9
|
+
|
|
10
|
+
cd "${ROOT_DIR}"
|
|
11
|
+
|
|
12
|
+
bun run build:app
|
|
13
|
+
concurrently -k -n opencode,server -c cyan,green \
|
|
14
|
+
"bun run dev:opencode" \
|
|
15
|
+
"bash -lc 'set -euo pipefail; echo \"[stack] waiting for OpenCode at ${OPENCODE_HEALTH_URL}\"; deadline=\$((SECONDS + ${STARTUP_TIMEOUT_SECONDS})); until curl -fsS \"${OPENCODE_HEALTH_URL}\" >/dev/null 2>&1; do if (( SECONDS >= deadline )); then echo \"[stack] timed out waiting for OpenCode health after ${STARTUP_TIMEOUT_SECONDS}s\"; exit 1; fi; sleep 0.25; done; echo \"[stack] OpenCode is healthy, starting Agent Mockingbird\"; exec bun run dev:server'"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
WAFFLEBOT_PORT="${PORT:-${AGENT_MOCKINGBIRD_PORT:-3001}}"
|
|
6
|
+
DEV_WORKSPACE_DIR="${AGENT_MOCKINGBIRD_MEMORY_WORKSPACE_DIR:-${ROOT_DIR}/data/workspace}"
|
|
7
|
+
DEV_CONFIG_PATH="${AGENT_MOCKINGBIRD_CONFIG_PATH:-${ROOT_DIR}/data/agent-mockingbird.dev-stack.config.json}"
|
|
8
|
+
DEV_OPENCODE_CONFIG_DIR="${AGENT_MOCKINGBIRD_OPENCODE_CONFIG_DIR:-${ROOT_DIR}/data/opencode-config/dev-stack}"
|
|
9
|
+
DEV_WORKSPACE_ASSETS_STATE_PATH="${AGENT_MOCKINGBIRD_RUNTIME_WORKSPACE_ASSETS_STATE_PATH:-${ROOT_DIR}/data/runtime-assets-workspace.dev-stack.json}"
|
|
10
|
+
DEV_OPENCODE_ASSETS_STATE_PATH="${AGENT_MOCKINGBIRD_RUNTIME_OPENCODE_ASSETS_STATE_PATH:-${ROOT_DIR}/data/runtime-assets-opencode-config.dev-stack.json}"
|
|
11
|
+
|
|
12
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
13
|
+
echo "bun is required but not found in PATH."
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
echo "[stack] syncing runtime assets into ${DEV_WORKSPACE_DIR}"
|
|
18
|
+
(
|
|
19
|
+
cd "${ROOT_DIR}"
|
|
20
|
+
bun scripts/runtime-assets-sync.mjs \
|
|
21
|
+
--source "${ROOT_DIR}/runtime-assets/workspace" \
|
|
22
|
+
--target "${DEV_WORKSPACE_DIR}" \
|
|
23
|
+
--state "${DEV_WORKSPACE_ASSETS_STATE_PATH}" \
|
|
24
|
+
--mode install \
|
|
25
|
+
--non-interactive \
|
|
26
|
+
--quiet
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
echo "[stack] syncing OpenCode config assets into ${DEV_OPENCODE_CONFIG_DIR}"
|
|
30
|
+
(
|
|
31
|
+
cd "${ROOT_DIR}"
|
|
32
|
+
bun scripts/runtime-assets-sync.mjs \
|
|
33
|
+
--source "${ROOT_DIR}/runtime-assets/opencode-config" \
|
|
34
|
+
--target "${DEV_OPENCODE_CONFIG_DIR}" \
|
|
35
|
+
--state "${DEV_OPENCODE_ASSETS_STATE_PATH}" \
|
|
36
|
+
--mode install \
|
|
37
|
+
--non-interactive \
|
|
38
|
+
--quiet
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if [[ -f "${DEV_OPENCODE_CONFIG_DIR}/package.json" ]]; then
|
|
42
|
+
echo "[stack] installing managed OpenCode config dependencies"
|
|
43
|
+
(
|
|
44
|
+
cd "${DEV_OPENCODE_CONFIG_DIR}"
|
|
45
|
+
bun install --frozen-lockfile >/dev/null
|
|
46
|
+
)
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
echo "[stack] starting agent-mockingbird on http://127.0.0.1:${WAFFLEBOT_PORT}"
|
|
50
|
+
echo "[stack] workspace: ${DEV_WORKSPACE_DIR}"
|
|
51
|
+
echo "[stack] opencode-config: ${DEV_OPENCODE_CONFIG_DIR}"
|
|
52
|
+
echo "[stack] config: ${DEV_CONFIG_PATH}"
|
|
53
|
+
|
|
54
|
+
cd "${ROOT_DIR}"
|
|
55
|
+
export PORT="${WAFFLEBOT_PORT}"
|
|
56
|
+
export AGENT_MOCKINGBIRD_PORT="${WAFFLEBOT_PORT}"
|
|
57
|
+
export AGENT_MOCKINGBIRD_MEMORY_WORKSPACE_DIR="${DEV_WORKSPACE_DIR}"
|
|
58
|
+
export AGENT_MOCKINGBIRD_CONFIG_PATH="${DEV_CONFIG_PATH}"
|
|
59
|
+
export OPENCODE_CONFIG_DIR="${DEV_OPENCODE_CONFIG_DIR}"
|
|
60
|
+
export OPENCODE_DISABLE_PROJECT_CONFIG="1"
|
|
61
|
+
exec bun --hot apps/server/src/index.ts
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
if [[ "${EUID}" -ne 0 ]]; then
|
|
5
|
+
echo "Run as root (sudo)."
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
APP_USER="${AGENT_MOCKINGBIRD_USER:-agent-mockingbird}"
|
|
10
|
+
APP_GROUP="${AGENT_MOCKINGBIRD_GROUP:-${APP_USER}}"
|
|
11
|
+
APP_DIR="${AGENT_MOCKINGBIRD_APP_DIR:-/srv/agent-mockingbird/app}"
|
|
12
|
+
DATA_DIR="${AGENT_MOCKINGBIRD_DATA_DIR:-/var/lib/agent-mockingbird}"
|
|
13
|
+
OPENCODE_CONFIG_DIR="${AGENT_MOCKINGBIRD_OPENCODE_CONFIG_DIR:-${DATA_DIR}/opencode-config/systemd}"
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
15
|
+
UNIT_DIR="/etc/systemd/system"
|
|
16
|
+
TMP_DIR="$(mktemp -d)"
|
|
17
|
+
|
|
18
|
+
cleanup() {
|
|
19
|
+
rm -rf "${TMP_DIR}"
|
|
20
|
+
}
|
|
21
|
+
trap cleanup EXIT
|
|
22
|
+
|
|
23
|
+
require_cmd() {
|
|
24
|
+
local cmd="$1"
|
|
25
|
+
if ! command -v "${cmd}" >/dev/null 2>&1; then
|
|
26
|
+
echo "${cmd} is required but not installed."
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
require_cmd bun
|
|
32
|
+
require_cmd opencode
|
|
33
|
+
require_cmd systemctl
|
|
34
|
+
require_cmd tar
|
|
35
|
+
|
|
36
|
+
if ! getent group "${APP_GROUP}" >/dev/null 2>&1; then
|
|
37
|
+
groupadd --system "${APP_GROUP}"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if ! id -u "${APP_USER}" >/dev/null 2>&1; then
|
|
41
|
+
useradd --system --home-dir "${APP_DIR}" --gid "${APP_GROUP}" --shell /usr/sbin/nologin "${APP_USER}"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
mkdir -p "${APP_DIR}" "${DATA_DIR}"
|
|
45
|
+
|
|
46
|
+
# Copy extracted release content into final app directory.
|
|
47
|
+
tar -C "${SCRIPT_DIR}" -cf - . | tar -C "${APP_DIR}" -xf -
|
|
48
|
+
|
|
49
|
+
chown -R "${APP_USER}:${APP_GROUP}" "${APP_DIR}" "${DATA_DIR}"
|
|
50
|
+
|
|
51
|
+
su -s /bin/bash -c "cd \"${APP_DIR}\" && bun install --frozen-lockfile" "${APP_USER}"
|
|
52
|
+
su -s /bin/bash -c "cd \"${APP_DIR}\" && bun scripts/runtime-assets-sync.mjs --source \"${APP_DIR}/runtime-assets/workspace\" --target \"${APP_DIR}\" --state \"${DATA_DIR}/runtime-assets-workspace-state.json\" --mode install --non-interactive" "${APP_USER}"
|
|
53
|
+
su -s /bin/bash -c "cd \"${APP_DIR}\" && bun scripts/runtime-assets-sync.mjs --source \"${APP_DIR}/runtime-assets/opencode-config\" --target \"${OPENCODE_CONFIG_DIR}\" --state \"${DATA_DIR}/runtime-assets-opencode-config-state.json\" --mode install --non-interactive" "${APP_USER}"
|
|
54
|
+
if [[ -f "${OPENCODE_CONFIG_DIR}/package.json" ]]; then
|
|
55
|
+
su -s /bin/bash -c "cd \"${OPENCODE_CONFIG_DIR}\" && bun install --frozen-lockfile" "${APP_USER}"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
render_unit() {
|
|
59
|
+
local src="$1"
|
|
60
|
+
local dst="$2"
|
|
61
|
+
|
|
62
|
+
sed \
|
|
63
|
+
-e "s|^User=.*$|User=${APP_USER}|" \
|
|
64
|
+
-e "s|^Group=.*$|Group=${APP_GROUP}|" \
|
|
65
|
+
-e "s|^WorkingDirectory=.*$|WorkingDirectory=${APP_DIR}|" \
|
|
66
|
+
-e "s|__AGENT_MOCKINGBIRD_OPENCODE_CONFIG_DIR__|${OPENCODE_CONFIG_DIR}|g" \
|
|
67
|
+
-e "s|/srv/agent-mockingbird/app|${APP_DIR}|g" \
|
|
68
|
+
-e "s|/var/lib/agent-mockingbird|${DATA_DIR}|g" \
|
|
69
|
+
"${src}" > "${dst}"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
render_unit "${APP_DIR}/deploy/systemd/opencode.service" "${TMP_DIR}/opencode.service"
|
|
73
|
+
render_unit "${APP_DIR}/deploy/systemd/agent-mockingbird.service" "${TMP_DIR}/agent-mockingbird.service"
|
|
74
|
+
|
|
75
|
+
install -m 0644 "${TMP_DIR}/opencode.service" "${UNIT_DIR}/opencode.service"
|
|
76
|
+
install -m 0644 "${TMP_DIR}/agent-mockingbird.service" "${UNIT_DIR}/agent-mockingbird.service"
|
|
77
|
+
|
|
78
|
+
systemctl daemon-reload
|
|
79
|
+
systemctl enable --now opencode.service agent-mockingbird.service
|
|
80
|
+
|
|
81
|
+
echo "Installed agent-mockingbird with systemd services:"
|
|
82
|
+
echo " opencode.service"
|
|
83
|
+
echo " agent-mockingbird.service"
|
|
84
|
+
echo
|
|
85
|
+
echo "Health checks:"
|
|
86
|
+
echo " curl -sS http://127.0.0.1:3001/api/health"
|
|
87
|
+
echo " systemctl status agent-mockingbird.service --no-pager"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
cd "${ROOT_DIR}"
|
|
6
|
+
|
|
7
|
+
if [[ -f ".env" ]]; then
|
|
8
|
+
while IFS= read -r line || [[ -n "${line}" ]]; do
|
|
9
|
+
if [[ "${line}" =~ ^[[:space:]]*# ]] || [[ "${line}" =~ ^[[:space:]]*$ ]]; then
|
|
10
|
+
continue
|
|
11
|
+
fi
|
|
12
|
+
if [[ "${line}" =~ ^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
|
|
13
|
+
key="${BASH_REMATCH[1]}"
|
|
14
|
+
value="${BASH_REMATCH[2]}"
|
|
15
|
+
if [[ -z "${!key+x}" ]]; then
|
|
16
|
+
export "${key}=${value}"
|
|
17
|
+
fi
|
|
18
|
+
fi
|
|
19
|
+
done < ".env"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
23
|
+
echo "[memory:e2e] bun is required but not found in PATH."
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if ! command -v curl >/dev/null 2>&1; then
|
|
28
|
+
echo "[memory:e2e] curl is required but not found in PATH."
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
MEMORY_ENABLED="${AGENT_MOCKINGBIRD_MEMORY_ENABLED:-true}"
|
|
33
|
+
EMBED_PROVIDER="${AGENT_MOCKINGBIRD_MEMORY_EMBED_PROVIDER:-ollama}"
|
|
34
|
+
OLLAMA_BASE_URL="${AGENT_MOCKINGBIRD_MEMORY_OLLAMA_BASE_URL:-http://127.0.0.1:11434}"
|
|
35
|
+
EMBED_MODEL="${AGENT_MOCKINGBIRD_MEMORY_EMBED_MODEL:-qwen3-embedding:4b}"
|
|
36
|
+
|
|
37
|
+
echo "[memory:e2e] starting"
|
|
38
|
+
echo "[memory:e2e] provider=${EMBED_PROVIDER} model=${EMBED_MODEL}"
|
|
39
|
+
|
|
40
|
+
if [[ "${MEMORY_ENABLED}" != "true" ]]; then
|
|
41
|
+
echo "[memory:e2e] AGENT_MOCKINGBIRD_MEMORY_ENABLED must be true."
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [[ "${EMBED_PROVIDER}" == "ollama" ]]; then
|
|
46
|
+
echo "[memory:e2e] checking ollama at ${OLLAMA_BASE_URL}"
|
|
47
|
+
if ! curl -fsS "${OLLAMA_BASE_URL}/api/tags" >/dev/null; then
|
|
48
|
+
echo "[memory:e2e] failed to reach Ollama tags endpoint."
|
|
49
|
+
echo "[memory:e2e] set AGENT_MOCKINGBIRD_MEMORY_OLLAMA_BASE_URL or run with AGENT_MOCKINGBIRD_MEMORY_EMBED_PROVIDER=none."
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
echo "[memory:e2e] memory status"
|
|
55
|
+
bun run src/backend/memory/cli.ts status
|
|
56
|
+
|
|
57
|
+
echo "[memory:e2e] forcing reindex"
|
|
58
|
+
bun run src/backend/memory/cli.ts reindex
|
|
59
|
+
|
|
60
|
+
MARKER="memory-e2e-$(date +%s)-$RANDOM"
|
|
61
|
+
CONTENT="E2E marker ${MARKER} created at $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
62
|
+
|
|
63
|
+
echo "[memory:e2e] writing marker"
|
|
64
|
+
bun run src/backend/memory/cli.ts remember fact "${CONTENT}" >/tmp/agent-mockingbird-memory-e2e-remember.json
|
|
65
|
+
|
|
66
|
+
echo "[memory:e2e] searching marker"
|
|
67
|
+
SEARCH_OUTPUT="$(bun run src/backend/memory/cli.ts search "${MARKER}")"
|
|
68
|
+
printf '%s\n' "${SEARCH_OUTPUT}" >/tmp/agent-mockingbird-memory-e2e-search.json
|
|
69
|
+
|
|
70
|
+
if [[ "${SEARCH_OUTPUT}" != *"${MARKER}"* ]]; then
|
|
71
|
+
echo "[memory:e2e] marker was not found in retrieval output."
|
|
72
|
+
echo "[memory:e2e] wrote debug output to /tmp/agent-mockingbird-memory-e2e-search.json"
|
|
73
|
+
exit 1
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
echo "[memory:e2e] PASS marker=${MARKER}"
|