soraacode 0.1.0
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.md +131 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/opencode +199 -0
- package/bin/soraacode +199 -0
- package/bunfig.toml +7 -0
- package/git +0 -0
- package/migration/20260511173437_session-metadata/migration.sql +1 -0
- package/migration/20260511173437_session-metadata/snapshot.json +1500 -0
- package/package.json +107 -0
- package/parsers-config.ts +1 -0
- package/script/bench-search.ts +94 -0
- package/script/bench-test-suite.ts +52 -0
- package/script/build-headless.ts +51 -0
- package/script/build.ts +245 -0
- package/script/generate.ts +14 -0
- package/script/httpapi-exercise.ts +1 -0
- package/script/postinstall.mjs +189 -0
- package/script/profile-test-files.ts +42 -0
- package/script/publish.ts +213 -0
- package/script/run-workspace-server +106 -0
- package/script/schema.ts +77 -0
- package/script/time.ts +6 -0
- package/script/trace-imports.ts +153 -0
- package/specs/effect/error-boundaries-plan.md +235 -0
- package/specs/effect/errors.md +207 -0
- package/specs/effect/facades.md +218 -0
- package/specs/effect/guide.md +247 -0
- package/specs/effect/instance-context.md +13 -0
- package/specs/effect/loose-ends.md +30 -0
- package/specs/effect/migration.md +62 -0
- package/specs/effect/routes.md +61 -0
- package/specs/effect/schema.md +88 -0
- package/specs/effect/server-package.md +58 -0
- package/specs/effect/todo.md +241 -0
- package/specs/effect/tools.md +88 -0
- package/specs/openapi-translation-cleanup.md +204 -0
- package/specs/tui-plugins.md +544 -0
- package/specs/v2/api.ts +67 -0
- package/specs/v2/message-shape.md +136 -0
- package/specs/v2/notifications.md +13 -0
- package/specs/v2/tui-command-shim.md +67 -0
- package/src/account/account.ts +481 -0
- package/src/account/repo.ts +171 -0
- package/src/account/schema.ts +99 -0
- package/src/account/url.ts +8 -0
- package/src/acp/agent.ts +95 -0
- package/src/acp/config-option.ts +206 -0
- package/src/acp/content.ts +269 -0
- package/src/acp/directory.ts +212 -0
- package/src/acp/error.ts +97 -0
- package/src/acp/event.ts +421 -0
- package/src/acp/permission.ts +254 -0
- package/src/acp/profile.ts +42 -0
- package/src/acp/service.ts +1226 -0
- package/src/acp/session.ts +232 -0
- package/src/acp/tool.ts +364 -0
- package/src/acp/usage.ts +243 -0
- package/src/agent/agent.ts +450 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +5 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +11 -0
- package/src/agent/prompt/title.txt +44 -0
- package/src/agent/subagent-permissions.ts +27 -0
- package/src/audio.d.ts +14 -0
- package/src/auth/index.ts +97 -0
- package/src/background/job.ts +37 -0
- package/src/bus/global.ts +22 -0
- package/src/cli/bootstrap.ts +11 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/serve.ts +24 -0
- package/src/cli/effect/prompt.ts +37 -0
- package/src/cli/effect-cmd.ts +96 -0
- package/src/cli/error.ts +130 -0
- package/src/cli/heap.ts +45 -0
- package/src/cli/logo.ts +2 -0
- package/src/cli/network.ts +80 -0
- package/src/cli/ui.ts +132 -0
- package/src/command/index.ts +177 -0
- package/src/command/template/initialize.txt +66 -0
- package/src/command/template/review.txt +101 -0
- package/src/config/agent.ts +59 -0
- package/src/config/command.ts +39 -0
- package/src/config/config.ts +707 -0
- package/src/config/entry-name.ts +19 -0
- package/src/config/managed.ts +69 -0
- package/src/config/markdown.ts +36 -0
- package/src/config/parse.ts +61 -0
- package/src/config/paths.ts +45 -0
- package/src/config/plugin.ts +79 -0
- package/src/config/v2-compat.ts +449 -0
- package/src/config/variable.ts +91 -0
- package/src/control-plane/adapters/index.ts +41 -0
- package/src/control-plane/adapters/worktree.ts +96 -0
- package/src/control-plane/dev/README.md +19 -0
- package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
- package/src/control-plane/types.ts +59 -0
- package/src/control-plane/util.ts +39 -0
- package/src/control-plane/workspace-adapter-runtime.ts +51 -0
- package/src/control-plane/workspace-context.ts +26 -0
- package/src/control-plane/workspace.ts +966 -0
- package/src/effect/app-node-builder-v1.ts +12 -0
- package/src/effect/app-runtime.ts +135 -0
- package/src/effect/bootstrap-runtime.ts +19 -0
- package/src/effect/bridge.ts +84 -0
- package/src/effect/config-service.ts +67 -0
- package/src/effect/instance-ref.ts +11 -0
- package/src/effect/instance-registry.ts +12 -0
- package/src/effect/instance-state.ts +69 -0
- package/src/effect/promise.ts +17 -0
- package/src/effect/run-service.ts +47 -0
- package/src/effect/runner.ts +217 -0
- package/src/effect/runtime-flags.ts +78 -0
- package/src/env/index.ts +41 -0
- package/src/event-manifest.ts +3 -0
- package/src/event-v2-bridge.ts +71 -0
- package/src/format/formatter.ts +404 -0
- package/src/format/index.ts +203 -0
- package/src/git/index.ts +348 -0
- package/src/id/id.ts +80 -0
- package/src/ide/index.ts +54 -0
- package/src/image/image.ts +172 -0
- package/src/index-headless.ts +89 -0
- package/src/index.ts +93 -0
- package/src/installation/index.ts +336 -0
- package/src/lsp/client.ts +650 -0
- package/src/lsp/diagnostic.ts +29 -0
- package/src/lsp/language.ts +121 -0
- package/src/lsp/launch.ts +21 -0
- package/src/lsp/lsp.ts +507 -0
- package/src/lsp/server.ts +1983 -0
- package/src/markdown.d.ts +4 -0
- package/src/mcp/auth.ts +163 -0
- package/src/mcp/browser.ts +37 -0
- package/src/mcp/catalog.ts +170 -0
- package/src/mcp/index.ts +1004 -0
- package/src/mcp/oauth-callback.ts +194 -0
- package/src/mcp/oauth-provider.ts +259 -0
- package/src/node.ts +4 -0
- package/src/patch/index.ts +686 -0
- package/src/permission/arity.ts +163 -0
- package/src/permission/evaluate.ts +1 -0
- package/src/permission/index.ts +223 -0
- package/src/plugin/github-copilot/copilot.ts +415 -0
- package/src/plugin/github-copilot/models.ts +261 -0
- package/src/plugin/index.ts +298 -0
- package/src/plugin/install.ts +439 -0
- package/src/plugin/loader.ts +237 -0
- package/src/plugin/meta.ts +188 -0
- package/src/plugin/openai/README.md +31 -0
- package/src/plugin/openai/codex.ts +575 -0
- package/src/plugin/openai/ws-pool.ts +271 -0
- package/src/plugin/openai/ws.ts +383 -0
- package/src/plugin/pty-environment.ts +24 -0
- package/src/plugin/shared.ts +323 -0
- package/src/project/bootstrap-service.ts +9 -0
- package/src/project/bootstrap.ts +58 -0
- package/src/project/instance-context.ts +24 -0
- package/src/project/instance-runtime.ts +16 -0
- package/src/project/instance-store.ts +213 -0
- package/src/project/project.ts +483 -0
- package/src/project/vcs.ts +423 -0
- package/src/provider/auth.ts +229 -0
- package/src/provider/error.ts +195 -0
- package/src/provider/model-status.ts +8 -0
- package/src/provider/provider.ts +1955 -0
- package/src/provider/transform.ts +1923 -0
- package/src/question/index.ts +161 -0
- package/src/question/schema.ts +4 -0
- package/src/server/auth.ts +48 -0
- package/src/server/event.ts +10 -0
- package/src/server/global-lifecycle.ts +28 -0
- package/src/server/mdns.ts +47 -0
- package/src/server/proxy-util.ts +48 -0
- package/src/server/routes/instance/httpapi/AGENTS.md +39 -0
- package/src/server/routes/instance/httpapi/api.ts +97 -0
- package/src/server/routes/instance/httpapi/errors.ts +193 -0
- package/src/server/routes/instance/httpapi/groups/config.ts +65 -0
- package/src/server/routes/instance/httpapi/groups/control-plane.ts +35 -0
- package/src/server/routes/instance/httpapi/groups/control.ts +76 -0
- package/src/server/routes/instance/httpapi/groups/event.ts +29 -0
- package/src/server/routes/instance/httpapi/groups/experimental.ts +275 -0
- package/src/server/routes/instance/httpapi/groups/file.ts +185 -0
- package/src/server/routes/instance/httpapi/groups/global.ts +139 -0
- package/src/server/routes/instance/httpapi/groups/instance.ts +206 -0
- package/src/server/routes/instance/httpapi/groups/mcp.ts +156 -0
- package/src/server/routes/instance/httpapi/groups/metadata.ts +18 -0
- package/src/server/routes/instance/httpapi/groups/permission.ts +61 -0
- package/src/server/routes/instance/httpapi/groups/project-copy.ts +32 -0
- package/src/server/routes/instance/httpapi/groups/project.ts +93 -0
- package/src/server/routes/instance/httpapi/groups/provider.ts +101 -0
- package/src/server/routes/instance/httpapi/groups/pty.ts +172 -0
- package/src/server/routes/instance/httpapi/groups/query.ts +12 -0
- package/src/server/routes/instance/httpapi/groups/question.ts +74 -0
- package/src/server/routes/instance/httpapi/groups/session.ts +462 -0
- package/src/server/routes/instance/httpapi/groups/sync.ts +113 -0
- package/src/server/routes/instance/httpapi/groups/tui.ts +208 -0
- package/src/server/routes/instance/httpapi/groups/workspace.ts +141 -0
- package/src/server/routes/instance/httpapi/handlers/config.ts +34 -0
- package/src/server/routes/instance/httpapi/handlers/control-plane.ts +37 -0
- package/src/server/routes/instance/httpapi/handlers/control.ts +43 -0
- package/src/server/routes/instance/httpapi/handlers/event.ts +99 -0
- package/src/server/routes/instance/httpapi/handlers/experimental.ts +193 -0
- package/src/server/routes/instance/httpapi/handlers/file.ts +139 -0
- package/src/server/routes/instance/httpapi/handlers/global.ts +126 -0
- package/src/server/routes/instance/httpapi/handlers/instance.ts +110 -0
- package/src/server/routes/instance/httpapi/handlers/mcp.ts +111 -0
- package/src/server/routes/instance/httpapi/handlers/permission.ts +41 -0
- package/src/server/routes/instance/httpapi/handlers/project-copy.ts +83 -0
- package/src/server/routes/instance/httpapi/handlers/project.ts +63 -0
- package/src/server/routes/instance/httpapi/handlers/provider.ts +116 -0
- package/src/server/routes/instance/httpapi/handlers/pty.ts +273 -0
- package/src/server/routes/instance/httpapi/handlers/question.ts +54 -0
- package/src/server/routes/instance/httpapi/handlers/session-errors.ts +21 -0
- package/src/server/routes/instance/httpapi/handlers/session.ts +442 -0
- package/src/server/routes/instance/httpapi/handlers/sync.ts +89 -0
- package/src/server/routes/instance/httpapi/handlers/tui.ts +131 -0
- package/src/server/routes/instance/httpapi/handlers/workspace.ts +102 -0
- package/src/server/routes/instance/httpapi/lifecycle.ts +54 -0
- package/src/server/routes/instance/httpapi/middleware/authorization.ts +150 -0
- package/src/server/routes/instance/httpapi/middleware/compression.ts +64 -0
- package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +29 -0
- package/src/server/routes/instance/httpapi/middleware/error.ts +44 -0
- package/src/server/routes/instance/httpapi/middleware/fence.ts +25 -0
- package/src/server/routes/instance/httpapi/middleware/instance-context.ts +43 -0
- package/src/server/routes/instance/httpapi/middleware/proxy.ts +131 -0
- package/src/server/routes/instance/httpapi/middleware/schema-error.ts +41 -0
- package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +250 -0
- package/src/server/routes/instance/httpapi/public.ts +537 -0
- package/src/server/routes/instance/httpapi/server.ts +325 -0
- package/src/server/routes/instance/httpapi/websocket-tracker.ts +60 -0
- package/src/server/server.ts +224 -0
- package/src/server/shared/fence.ts +60 -0
- package/src/server/shared/pty-ticket.ts +15 -0
- package/src/server/shared/public-ui.ts +12 -0
- package/src/server/shared/tui-control.ts +28 -0
- package/src/server/shared/ui.ts +108 -0
- package/src/server/shared/workspace-routing.ts +45 -0
- package/src/server/tui-event.ts +1 -0
- package/src/session/compaction.ts +608 -0
- package/src/session/instruction.ts +237 -0
- package/src/session/llm/AGENTS.md +90 -0
- package/src/session/llm/ai-sdk.ts +291 -0
- package/src/session/llm/native-request.ts +196 -0
- package/src/session/llm/native-runtime.ts +195 -0
- package/src/session/llm/request.ts +226 -0
- package/src/session/llm.ts +390 -0
- package/src/session/message-error.ts +14 -0
- package/src/session/message-v2.ts +742 -0
- package/src/session/message.ts +148 -0
- package/src/session/overflow.ts +34 -0
- package/src/session/processor.ts +732 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/default.txt +35 -0
- package/src/session/prompt/plan-mode.txt +70 -0
- package/src/session/prompt/plan.txt +26 -0
- package/src/session/prompt.ts +1631 -0
- package/src/session/reminders.ts +92 -0
- package/src/session/retry.ts +209 -0
- package/src/session/revert.ts +136 -0
- package/src/session/run-state.ts +151 -0
- package/src/session/schema.ts +26 -0
- package/src/session/session.ts +1016 -0
- package/src/session/status.ts +56 -0
- package/src/session/summary.ts +160 -0
- package/src/session/system.ts +123 -0
- package/src/session/todo.ts +74 -0
- package/src/session/tools.ts +590 -0
- package/src/share/session.ts +58 -0
- package/src/share/share-next.ts +371 -0
- package/src/skill/discovery.ts +140 -0
- package/src/skill/index.ts +354 -0
- package/src/snapshot/index.ts +807 -0
- package/src/sql.d.ts +4 -0
- package/src/storage/schema.ts +5 -0
- package/src/storage/storage.ts +327 -0
- package/src/sync/README.md +179 -0
- package/src/sync/schema.ts +11 -0
- package/src/temporary.ts +31 -0
- package/src/tool/apply_patch.ts +313 -0
- package/src/tool/apply_patch.txt +14 -0
- package/src/tool/code-mode.ts +310 -0
- package/src/tool/edit.ts +737 -0
- package/src/tool/edit.txt +13 -0
- package/src/tool/external-directory.ts +49 -0
- package/src/tool/glob.ts +76 -0
- package/src/tool/glob.txt +7 -0
- package/src/tool/grep.ts +115 -0
- package/src/tool/grep.txt +7 -0
- package/src/tool/invalid.ts +21 -0
- package/src/tool/json-schema.ts +164 -0
- package/src/tool/lsp.ts +113 -0
- package/src/tool/lsp.txt +1 -0
- package/src/tool/mcp-websearch.ts +96 -0
- package/src/tool/plan-enter.txt +1 -0
- package/src/tool/plan-exit.txt +1 -0
- package/src/tool/plan.ts +79 -0
- package/src/tool/question.ts +44 -0
- package/src/tool/question.txt +1 -0
- package/src/tool/read.ts +386 -0
- package/src/tool/read.txt +13 -0
- package/src/tool/registry.ts +455 -0
- package/src/tool/schema.ts +14 -0
- package/src/tool/shell/id.ts +19 -0
- package/src/tool/shell/prompt.ts +293 -0
- package/src/tool/shell/shell.txt +21 -0
- package/src/tool/shell.ts +645 -0
- package/src/tool/skill.ts +70 -0
- package/src/tool/skill.txt +1 -0
- package/src/tool/task.ts +371 -0
- package/src/tool/task.txt +11 -0
- package/src/tool/todo.ts +46 -0
- package/src/tool/todowrite.txt +11 -0
- package/src/tool/tool.ts +183 -0
- package/src/tool/truncate.ts +156 -0
- package/src/tool/truncation-dir.ts +4 -0
- package/src/tool/webfetch.ts +192 -0
- package/src/tool/webfetch.txt +9 -0
- package/src/tool/websearch.ts +143 -0
- package/src/tool/websearch.txt +9 -0
- package/src/tool/write.ts +104 -0
- package/src/tool/write.txt +11 -0
- package/src/util/archive.ts +17 -0
- package/src/util/bom.ts +27 -0
- package/src/util/data-url.ts +9 -0
- package/src/util/defer.ts +10 -0
- package/src/util/effect-http-client.ts +11 -0
- package/src/util/error.ts +16 -0
- package/src/util/filesystem.ts +251 -0
- package/src/util/html.ts +8 -0
- package/src/util/iife.ts +3 -0
- package/src/util/lazy.ts +20 -0
- package/src/util/local-context.ts +25 -0
- package/src/util/locale.ts +4 -0
- package/src/util/media.ts +26 -0
- package/src/util/process.ts +177 -0
- package/src/util/proxy-env.ts +72 -0
- package/src/util/queue.ts +32 -0
- package/src/util/record.ts +3 -0
- package/src/util/repository.ts +232 -0
- package/src/util/rpc.ts +66 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +13 -0
- package/src/util/token.ts +1 -0
- package/src/util/wildcard.ts +59 -0
- package/src/worktree/index.ts +623 -0
- package/sst-env.d.ts +10 -0
- package/tsconfig.headless.json +13 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import childProcess from "child_process"
|
|
4
|
+
import fs from "fs"
|
|
5
|
+
import os from "os"
|
|
6
|
+
import path from "path"
|
|
7
|
+
import { createRequire } from "module"
|
|
8
|
+
import { fileURLToPath } from "url"
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
const require = createRequire(import.meta.url)
|
|
12
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
|
|
13
|
+
|
|
14
|
+
const platformMap = {
|
|
15
|
+
darwin: "darwin",
|
|
16
|
+
linux: "linux",
|
|
17
|
+
win32: "windows",
|
|
18
|
+
}
|
|
19
|
+
const archMap = {
|
|
20
|
+
x64: "x64",
|
|
21
|
+
arm64: "arm64",
|
|
22
|
+
arm: "arm",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const platform = platformMap[os.platform()] ?? os.platform()
|
|
26
|
+
const arch = archMap[os.arch()] ?? os.arch()
|
|
27
|
+
const base = `opencode-${platform}-${arch}`
|
|
28
|
+
const sourceBinary = platform === "windows" ? "opencode.exe" : "opencode"
|
|
29
|
+
const targetBinary = path.join(__dirname, "bin", "opencode.exe")
|
|
30
|
+
|
|
31
|
+
function supportsAvx2() {
|
|
32
|
+
if (arch !== "x64") return false
|
|
33
|
+
|
|
34
|
+
if (platform === "linux") {
|
|
35
|
+
try {
|
|
36
|
+
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
|
37
|
+
} catch {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (platform === "darwin") {
|
|
43
|
+
try {
|
|
44
|
+
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
|
45
|
+
encoding: "utf8",
|
|
46
|
+
timeout: 1500,
|
|
47
|
+
})
|
|
48
|
+
if (result.status !== 0) return false
|
|
49
|
+
return (result.stdout || "").trim() === "1"
|
|
50
|
+
} catch {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (platform === "windows") {
|
|
56
|
+
const command =
|
|
57
|
+
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
|
58
|
+
|
|
59
|
+
for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
60
|
+
try {
|
|
61
|
+
const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
|
|
62
|
+
encoding: "utf8",
|
|
63
|
+
timeout: 3000,
|
|
64
|
+
windowsHide: true,
|
|
65
|
+
})
|
|
66
|
+
if (result.status !== 0) continue
|
|
67
|
+
const output = (result.stdout || "").trim().toLowerCase()
|
|
68
|
+
if (output === "true" || output === "1") return true
|
|
69
|
+
if (output === "false" || output === "0") return false
|
|
70
|
+
} catch {
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isMusl() {
|
|
80
|
+
if (platform !== "linux") return false
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
if (fs.existsSync("/etc/alpine-release")) return true
|
|
84
|
+
} catch {
|
|
85
|
+
// Ignore filesystem probes that are blocked by the host.
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
90
|
+
return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
|
|
91
|
+
} catch {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function packageNames() {
|
|
97
|
+
const baseline = arch === "x64" && !supportsAvx2()
|
|
98
|
+
|
|
99
|
+
if (platform === "linux") {
|
|
100
|
+
if (isMusl()) {
|
|
101
|
+
if (arch === "x64")
|
|
102
|
+
return baseline
|
|
103
|
+
? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
|
104
|
+
: [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
|
105
|
+
return [`${base}-musl`, base]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (arch === "x64")
|
|
109
|
+
return baseline
|
|
110
|
+
? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
|
111
|
+
: [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
|
112
|
+
return [base, `${base}-musl`]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
|
|
116
|
+
return [base]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function resolveBinary(name) {
|
|
120
|
+
const packageJsonPath = require.resolve(`${name}/package.json`)
|
|
121
|
+
const binaryPath = path.join(path.dirname(packageJsonPath), "bin", sourceBinary)
|
|
122
|
+
if (!fs.existsSync(binaryPath)) throw new Error(`Binary not found at ${binaryPath}`)
|
|
123
|
+
return binaryPath
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function installPackage(name) {
|
|
127
|
+
const version = packageJson.optionalDependencies?.[name]
|
|
128
|
+
if (!version) return
|
|
129
|
+
|
|
130
|
+
const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-"))
|
|
131
|
+
try {
|
|
132
|
+
const result = childProcess.spawnSync(
|
|
133
|
+
"npm",
|
|
134
|
+
["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${name}@${version}`],
|
|
135
|
+
{ stdio: "inherit", windowsHide: true },
|
|
136
|
+
)
|
|
137
|
+
if (result.status !== 0) return
|
|
138
|
+
const packageDir = path.join(temp, "node_modules", name)
|
|
139
|
+
copyBinary(path.join(packageDir, "bin", sourceBinary), targetBinary)
|
|
140
|
+
return true
|
|
141
|
+
} finally {
|
|
142
|
+
fs.rmSync(temp, { recursive: true, force: true })
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function copyBinary(source, target) {
|
|
147
|
+
if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
|
|
148
|
+
fs.mkdirSync(path.dirname(target), { recursive: true })
|
|
149
|
+
if (fs.existsSync(target)) fs.unlinkSync(target)
|
|
150
|
+
try {
|
|
151
|
+
fs.linkSync(source, target)
|
|
152
|
+
} catch {
|
|
153
|
+
fs.copyFileSync(source, target)
|
|
154
|
+
}
|
|
155
|
+
fs.chmodSync(target, 0o755)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function verifyBinary() {
|
|
159
|
+
const result = childProcess.spawnSync(targetBinary, ["--version"], {
|
|
160
|
+
encoding: "utf8",
|
|
161
|
+
stdio: "ignore",
|
|
162
|
+
windowsHide: true,
|
|
163
|
+
})
|
|
164
|
+
return result.status === 0
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function main() {
|
|
168
|
+
for (const name of packageNames()) {
|
|
169
|
+
try {
|
|
170
|
+
copyBinary(resolveBinary(name), targetBinary)
|
|
171
|
+
if (verifyBinary()) return
|
|
172
|
+
} catch {
|
|
173
|
+
if (installPackage(name) && verifyBinary()) return
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
throw new Error(
|
|
178
|
+
`It seems your package manager failed to install the right opencode CLI package. Try manually installing ${packageNames()
|
|
179
|
+
.map((name) => JSON.stringify(name))
|
|
180
|
+
.join(" or ")}.`,
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
main()
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.error(error.message)
|
|
188
|
+
process.exit(1)
|
|
189
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Per-file profiler for finding candidate test-speed work; see ../../perf/test-suite.md
|
|
2
|
+
// for the benchmark notes, kept wins, and discarded experiments.
|
|
3
|
+
// Example: TEST_PROFILE_GLOB='test/server/**/*.test.ts' TEST_PROFILE_TOP=15 bun run profile:test
|
|
4
|
+
const pattern = Bun.env.TEST_PROFILE_GLOB ?? "test/**/*.test.{ts,tsx}"
|
|
5
|
+
const limit = Number(Bun.env.TEST_PROFILE_LIMIT ?? 0)
|
|
6
|
+
const timeout = Bun.env.TEST_PROFILE_TIMEOUT ?? "30000"
|
|
7
|
+
const files = Array.fromAsync(new Bun.Glob(pattern).scan({ cwd: import.meta.dir + "/..", onlyFiles: true }))
|
|
8
|
+
.then((files) => files.toSorted())
|
|
9
|
+
.then((files) => (limit > 0 ? files.slice(0, limit) : files))
|
|
10
|
+
|
|
11
|
+
const results = []
|
|
12
|
+
for (const file of await files) {
|
|
13
|
+
const start = performance.now()
|
|
14
|
+
const proc = Bun.spawn(["bun", "test", "--timeout", timeout, file], {
|
|
15
|
+
cwd: import.meta.dir + "/..",
|
|
16
|
+
stdout: "pipe",
|
|
17
|
+
stderr: "pipe",
|
|
18
|
+
env: Bun.env,
|
|
19
|
+
})
|
|
20
|
+
const [output, error, exitCode] = await Promise.all([
|
|
21
|
+
new Response(proc.stdout).text(),
|
|
22
|
+
new Response(proc.stderr).text(),
|
|
23
|
+
proc.exited,
|
|
24
|
+
])
|
|
25
|
+
const seconds = (performance.now() - start) / 1000
|
|
26
|
+
results.push({ file, seconds, exitCode })
|
|
27
|
+
console.log(`${exitCode === 0 ? "PASS" : "FAIL"} ${seconds.toFixed(3)}s ${file}`)
|
|
28
|
+
if (exitCode !== 0) console.log((output + error).trim())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const sorted = results.toSorted((a, b) => b.seconds - a.seconds)
|
|
32
|
+
console.log("\nSlowest test files:")
|
|
33
|
+
for (const result of sorted.slice(0, Number(Bun.env.TEST_PROFILE_TOP ?? 20))) {
|
|
34
|
+
console.log(`${result.seconds.toFixed(3)}s ${result.exitCode === 0 ? "PASS" : "FAIL"} ${result.file}`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (sorted[0]) {
|
|
38
|
+
console.log(`METRIC slowest_test_file_seconds=${sorted[0].seconds.toFixed(3)}`)
|
|
39
|
+
console.log(`METRIC profiled_test_files=${results.length}`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (results.some((result) => result.exitCode !== 0)) process.exit(1)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { $ } from "bun"
|
|
3
|
+
import pkg from "../package.json"
|
|
4
|
+
import { Script } from "@opencode-ai/script"
|
|
5
|
+
import { fileURLToPath } from "url"
|
|
6
|
+
|
|
7
|
+
const dir = fileURLToPath(new URL("..", import.meta.url))
|
|
8
|
+
process.chdir(dir)
|
|
9
|
+
|
|
10
|
+
async function published(name: string, version: string) {
|
|
11
|
+
return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function publish(dir: string, name: string, version: string) {
|
|
15
|
+
// GitHub artifact downloads can drop the executable bit, and Docker uses the
|
|
16
|
+
// unpacked dist binaries directly rather than the published tarball.
|
|
17
|
+
if (process.platform !== "win32") await $`chmod -R 755 .`.cwd(dir)
|
|
18
|
+
if (await published(name, version)) {
|
|
19
|
+
console.log(`already published ${name}@${version}`)
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
await $`bun pm pack`.cwd(dir)
|
|
23
|
+
await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(dir)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const binaries: Record<string, string> = {}
|
|
27
|
+
for (const filepath of new Bun.Glob("*/package.json").scanSync({ cwd: "./dist" })) {
|
|
28
|
+
const pkg = await Bun.file(`./dist/${filepath}`).json()
|
|
29
|
+
binaries[pkg.name] = pkg.version
|
|
30
|
+
}
|
|
31
|
+
console.log("binaries", binaries)
|
|
32
|
+
const version = Object.values(binaries)[0]
|
|
33
|
+
|
|
34
|
+
await $`mkdir -p ./dist/${pkg.name}`
|
|
35
|
+
await $`mkdir -p ./dist/${pkg.name}/bin`
|
|
36
|
+
await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs`
|
|
37
|
+
await Bun.file(`./dist/${pkg.name}/LICENSE`).write(await Bun.file("../../LICENSE").text())
|
|
38
|
+
await Bun.file(`./dist/${pkg.name}/bin/${pkg.name}.exe`).write(
|
|
39
|
+
[
|
|
40
|
+
`echo "Error: ${pkg.name}-ai's postinstall script was not run." >&2`,
|
|
41
|
+
'echo "" >&2',
|
|
42
|
+
'echo "This occurs when using --ignore-scripts during installation, or when using a" >&2',
|
|
43
|
+
'echo "package manager like pnpm that does not run postinstall scripts by default." >&2',
|
|
44
|
+
'echo "" >&2',
|
|
45
|
+
'echo "To fix this, run the postinstall script manually:" >&2',
|
|
46
|
+
`echo " cd node_modules/${pkg.name}-ai && node postinstall.mjs" >&2`,
|
|
47
|
+
'echo "" >&2',
|
|
48
|
+
`echo "Or reinstall ${pkg.name}-ai without the --ignore-scripts flag." >&2`,
|
|
49
|
+
"exit 1",
|
|
50
|
+
"",
|
|
51
|
+
].join("\n"),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
await Bun.file(`./dist/${pkg.name}/package.json`).write(
|
|
55
|
+
JSON.stringify(
|
|
56
|
+
{
|
|
57
|
+
name: pkg.name + "-ai",
|
|
58
|
+
bin: {
|
|
59
|
+
[pkg.name]: `./bin/${pkg.name}.exe`,
|
|
60
|
+
},
|
|
61
|
+
scripts: {
|
|
62
|
+
postinstall: "node ./postinstall.mjs",
|
|
63
|
+
},
|
|
64
|
+
version: version,
|
|
65
|
+
license: pkg.license,
|
|
66
|
+
os: ["darwin", "linux", "win32"],
|
|
67
|
+
cpu: ["arm64", "x64"],
|
|
68
|
+
optionalDependencies: binaries,
|
|
69
|
+
},
|
|
70
|
+
null,
|
|
71
|
+
2,
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
const tasks = Object.entries(binaries).map(async ([name]) => {
|
|
76
|
+
await publish(`./dist/${name}`, name, binaries[name])
|
|
77
|
+
})
|
|
78
|
+
await Promise.all(tasks)
|
|
79
|
+
await publish(`./dist/${pkg.name}`, `${pkg.name}-ai`, version)
|
|
80
|
+
|
|
81
|
+
const image = "ghcr.io/anomalyco/opencode"
|
|
82
|
+
const platforms = "linux/amd64,linux/arm64"
|
|
83
|
+
const tags = [`${image}:${version}`, `${image}:${Script.channel}`]
|
|
84
|
+
const tagFlags = tags.flatMap((t) => ["-t", t])
|
|
85
|
+
|
|
86
|
+
// registries
|
|
87
|
+
if (!Script.preview) {
|
|
88
|
+
await $`docker buildx build --platform ${platforms} ${tagFlags} --push .`
|
|
89
|
+
// Calculate SHA values
|
|
90
|
+
const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
91
|
+
const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
92
|
+
const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
93
|
+
const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
94
|
+
|
|
95
|
+
const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2)
|
|
96
|
+
|
|
97
|
+
// arch
|
|
98
|
+
const binaryPkgbuild = [
|
|
99
|
+
"# Maintainer: dax",
|
|
100
|
+
"# Maintainer: adam",
|
|
101
|
+
"",
|
|
102
|
+
"pkgname='opencode-bin'",
|
|
103
|
+
`pkgver=${pkgver}`,
|
|
104
|
+
`_subver=${_subver}`,
|
|
105
|
+
"options=('!debug' '!strip')",
|
|
106
|
+
"pkgrel=1",
|
|
107
|
+
"pkgdesc='The AI coding agent built for the terminal.'",
|
|
108
|
+
"url='https://github.com/anomalyco/opencode'",
|
|
109
|
+
"arch=('aarch64' 'x86_64')",
|
|
110
|
+
"license=('MIT')",
|
|
111
|
+
"provides=('opencode')",
|
|
112
|
+
"conflicts=('opencode')",
|
|
113
|
+
"depends=('ripgrep')",
|
|
114
|
+
"",
|
|
115
|
+
`source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-arm64.tar.gz")`,
|
|
116
|
+
`sha256sums_aarch64=('${arm64Sha}')`,
|
|
117
|
+
|
|
118
|
+
`source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-x64.tar.gz")`,
|
|
119
|
+
`sha256sums_x86_64=('${x64Sha}')`,
|
|
120
|
+
"",
|
|
121
|
+
"package() {",
|
|
122
|
+
' install -Dm755 ./opencode "${pkgdir}/usr/bin/opencode"',
|
|
123
|
+
"}",
|
|
124
|
+
"",
|
|
125
|
+
].join("\n")
|
|
126
|
+
|
|
127
|
+
for (const [pkg, pkgbuild] of [["opencode-bin", binaryPkgbuild]]) {
|
|
128
|
+
for (let i = 0; i < 30; i++) {
|
|
129
|
+
try {
|
|
130
|
+
await $`rm -rf ./dist/aur-${pkg}`
|
|
131
|
+
await $`git clone ssh://aur@aur.archlinux.org/${pkg}.git ./dist/aur-${pkg}`
|
|
132
|
+
await $`cd ./dist/aur-${pkg} && git checkout master`
|
|
133
|
+
await Bun.file(`./dist/aur-${pkg}/PKGBUILD`).write(pkgbuild)
|
|
134
|
+
await $`cd ./dist/aur-${pkg} && makepkg --printsrcinfo > .SRCINFO`
|
|
135
|
+
await $`cd ./dist/aur-${pkg} && git add PKGBUILD .SRCINFO`
|
|
136
|
+
if ((await $`cd ./dist/aur-${pkg} && git diff --cached --quiet`.nothrow()).exitCode === 0) break
|
|
137
|
+
await $`cd ./dist/aur-${pkg} && git commit -m "Update to v${Script.version}"`
|
|
138
|
+
await $`cd ./dist/aur-${pkg} && git push`
|
|
139
|
+
break
|
|
140
|
+
} catch {
|
|
141
|
+
continue
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Homebrew formula
|
|
147
|
+
const homebrewFormula = [
|
|
148
|
+
"# typed: false",
|
|
149
|
+
"# frozen_string_literal: true",
|
|
150
|
+
"",
|
|
151
|
+
"# This file was generated by GoReleaser. DO NOT EDIT.",
|
|
152
|
+
"class Opencode < Formula",
|
|
153
|
+
` desc "The AI coding agent built for the terminal."`,
|
|
154
|
+
` homepage "https://github.com/anomalyco/opencode"`,
|
|
155
|
+
` version "${Script.version.split("-")[0]}"`,
|
|
156
|
+
"",
|
|
157
|
+
` depends_on "ripgrep"`,
|
|
158
|
+
"",
|
|
159
|
+
" on_macos do",
|
|
160
|
+
" if Hardware::CPU.intel?",
|
|
161
|
+
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`,
|
|
162
|
+
` sha256 "${macX64Sha}"`,
|
|
163
|
+
"",
|
|
164
|
+
" def install",
|
|
165
|
+
' bin.install "opencode"',
|
|
166
|
+
" end",
|
|
167
|
+
" end",
|
|
168
|
+
" if Hardware::CPU.arm?",
|
|
169
|
+
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-arm64.zip"`,
|
|
170
|
+
` sha256 "${macArm64Sha}"`,
|
|
171
|
+
"",
|
|
172
|
+
" def install",
|
|
173
|
+
' bin.install "opencode"',
|
|
174
|
+
" end",
|
|
175
|
+
" end",
|
|
176
|
+
" end",
|
|
177
|
+
"",
|
|
178
|
+
" on_linux do",
|
|
179
|
+
" if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?",
|
|
180
|
+
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-x64.tar.gz"`,
|
|
181
|
+
` sha256 "${x64Sha}"`,
|
|
182
|
+
" def install",
|
|
183
|
+
' bin.install "opencode"',
|
|
184
|
+
" end",
|
|
185
|
+
" end",
|
|
186
|
+
" if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?",
|
|
187
|
+
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-arm64.tar.gz"`,
|
|
188
|
+
` sha256 "${arm64Sha}"`,
|
|
189
|
+
" def install",
|
|
190
|
+
' bin.install "opencode"',
|
|
191
|
+
" end",
|
|
192
|
+
" end",
|
|
193
|
+
" end",
|
|
194
|
+
"end",
|
|
195
|
+
"",
|
|
196
|
+
"",
|
|
197
|
+
].join("\n")
|
|
198
|
+
|
|
199
|
+
const token = process.env.GITHUB_TOKEN
|
|
200
|
+
if (!token) {
|
|
201
|
+
console.error("GITHUB_TOKEN is required to update homebrew tap")
|
|
202
|
+
process.exit(1)
|
|
203
|
+
}
|
|
204
|
+
const tap = `https://x-access-token:${token}@github.com/anomalyco/homebrew-tap.git`
|
|
205
|
+
await $`rm -rf ./dist/homebrew-tap`
|
|
206
|
+
await $`git clone ${tap} ./dist/homebrew-tap`
|
|
207
|
+
await Bun.file("./dist/homebrew-tap/opencode.rb").write(homebrewFormula)
|
|
208
|
+
await $`cd ./dist/homebrew-tap && git add opencode.rb`
|
|
209
|
+
if ((await $`cd ./dist/homebrew-tap && git diff --cached --quiet`.nothrow()).exitCode !== 0) {
|
|
210
|
+
await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"`
|
|
211
|
+
await $`cd ./dist/homebrew-tap && git push`
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
// This script runs a separate OpenCode server to be used as a remote
|
|
4
|
+
// workspace, simulating a remote environment but all local to make
|
|
5
|
+
// debugger easier
|
|
6
|
+
//
|
|
7
|
+
// *Important*: make sure you add the debug workspace plugin first.
|
|
8
|
+
// In `.opencode/opencode.jsonc` in the root of this project add:
|
|
9
|
+
//
|
|
10
|
+
// "plugin": ["../packages/opencode/src/control-plane/dev/debug-workspace-plugin.ts"]
|
|
11
|
+
//
|
|
12
|
+
// Afterwards, run `./packages/opencode/script/run-workspace-server`
|
|
13
|
+
|
|
14
|
+
import { stat } from "node:fs/promises"
|
|
15
|
+
import { setTimeout as sleep } from "node:timers/promises"
|
|
16
|
+
|
|
17
|
+
const DEV_DATA_FILE = "/tmp/opencode-workspace-dev-data.json"
|
|
18
|
+
const RESTART_POLL_INTERVAL = 250
|
|
19
|
+
|
|
20
|
+
async function readData() {
|
|
21
|
+
return await Bun.file(DEV_DATA_FILE).json()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function readDataMtime() {
|
|
25
|
+
return await stat(DEV_DATA_FILE)
|
|
26
|
+
.then((info) => info.mtimeMs)
|
|
27
|
+
.catch((error) => {
|
|
28
|
+
if (typeof error === "object" && error && "code" in error && error.code === "ENOENT") {
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw error
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function readSnapshot() {
|
|
37
|
+
while (true) {
|
|
38
|
+
try {
|
|
39
|
+
const before = await readDataMtime()
|
|
40
|
+
if (before === undefined) {
|
|
41
|
+
await sleep(RESTART_POLL_INTERVAL)
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const data = await readData()
|
|
46
|
+
const after = await readDataMtime()
|
|
47
|
+
|
|
48
|
+
if (before === after) {
|
|
49
|
+
return { data, mtime: after }
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (typeof error === "object" && error && "code" in error && error.code === "ENOENT") {
|
|
53
|
+
await sleep(RESTART_POLL_INTERVAL)
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
throw error
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function startDevServer(data: any) {
|
|
63
|
+
const env = Object.fromEntries(Object.entries(data.env ?? {}).filter(([, value]) => value !== undefined))
|
|
64
|
+
|
|
65
|
+
return Bun.spawn(["bun", "run", "dev", "serve", "--port", String(data.port), "--print-logs"], {
|
|
66
|
+
env: {
|
|
67
|
+
...process.env,
|
|
68
|
+
...env,
|
|
69
|
+
XDG_DATA_HOME: "/tmp/data",
|
|
70
|
+
},
|
|
71
|
+
stdin: "inherit",
|
|
72
|
+
stdout: "inherit",
|
|
73
|
+
stderr: "inherit",
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function waitForRestartSignal(mtime: number, signal: AbortSignal) {
|
|
78
|
+
while (!signal.aborted) {
|
|
79
|
+
await sleep(RESTART_POLL_INTERVAL)
|
|
80
|
+
if (signal.aborted) return false
|
|
81
|
+
if ((await readDataMtime()) !== mtime) return true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
while (true) {
|
|
88
|
+
const { data, mtime } = await readSnapshot()
|
|
89
|
+
const proc = startDevServer(data)
|
|
90
|
+
const restartAbort = new AbortController()
|
|
91
|
+
|
|
92
|
+
const result = await Promise.race([
|
|
93
|
+
proc.exited.then((code) => ({ type: "exit" as const, code })),
|
|
94
|
+
waitForRestartSignal(mtime, restartAbort.signal).then((restart) => ({ type: "restart" as const, restart })),
|
|
95
|
+
])
|
|
96
|
+
|
|
97
|
+
restartAbort.abort()
|
|
98
|
+
|
|
99
|
+
if (result.type === "restart" && result.restart) {
|
|
100
|
+
proc.kill()
|
|
101
|
+
await proc.exited
|
|
102
|
+
continue
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
process.exit(result.code)
|
|
106
|
+
}
|
package/script/schema.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Config } from "@/config/config"
|
|
4
|
+
import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
|
|
5
|
+
import { TuiConfig } from "@opencode-ai/tui/config"
|
|
6
|
+
import { Schema } from "effect"
|
|
7
|
+
|
|
8
|
+
type JsonSchema = Record<string, unknown>
|
|
9
|
+
const MODEL_REF = "https://models.dev/model-schema.json#/$defs/Model"
|
|
10
|
+
|
|
11
|
+
function generateEffect(schema: Schema.Top) {
|
|
12
|
+
const document = Schema.toJsonSchemaDocument(schema)
|
|
13
|
+
const normalized = normalize({
|
|
14
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
15
|
+
...document.schema,
|
|
16
|
+
$defs: document.definitions,
|
|
17
|
+
})
|
|
18
|
+
if (!isRecord(normalized)) throw new Error("schema generator produced a non-object schema")
|
|
19
|
+
const restored = restoreModelRefs(normalized)
|
|
20
|
+
if (!isRecord(restored)) throw new Error("schema generator produced a non-object schema")
|
|
21
|
+
restored.allowComments = true
|
|
22
|
+
restored.allowTrailingCommas = true
|
|
23
|
+
return restored
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalize(value: unknown): unknown {
|
|
27
|
+
if (Array.isArray(value)) return value.map(normalize)
|
|
28
|
+
if (!isRecord(value)) return value
|
|
29
|
+
|
|
30
|
+
const schema = Object.fromEntries(Object.entries(value).map(([key, item]) => [key, normalize(item)]))
|
|
31
|
+
|
|
32
|
+
if (Array.isArray(schema.anyOf)) {
|
|
33
|
+
const anyOf = schema.anyOf.filter((item) => !isRecord(item) || item.type !== "null")
|
|
34
|
+
if (anyOf.length !== schema.anyOf.length) {
|
|
35
|
+
const { anyOf: _, ...rest } = schema
|
|
36
|
+
if (anyOf.length === 1 && isRecord(anyOf[0])) return normalize({ ...anyOf[0], ...rest })
|
|
37
|
+
return { ...rest, anyOf }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (Array.isArray(schema.allOf) && schema.allOf.length === 1 && isRecord(schema.allOf[0])) {
|
|
42
|
+
const { allOf: _, ...rest } = schema
|
|
43
|
+
return normalize({ ...schema.allOf[0], ...rest })
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (schema.type === "integer" && schema.maximum === undefined) {
|
|
47
|
+
return { ...schema, maximum: Number.MAX_SAFE_INTEGER }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return schema
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function restoreModelRefs(value: unknown, key?: string): unknown {
|
|
54
|
+
if (Array.isArray(value)) return value.map((item) => restoreModelRefs(item))
|
|
55
|
+
if (!isRecord(value)) return value
|
|
56
|
+
|
|
57
|
+
const schema = Object.fromEntries(Object.entries(value).map(([name, item]) => [name, restoreModelRefs(item, name)]))
|
|
58
|
+
if ((key === "model" || key === "small_model") && schema.type === "string") {
|
|
59
|
+
return { ...schema, $ref: MODEL_REF }
|
|
60
|
+
}
|
|
61
|
+
return schema
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isRecord(value: unknown): value is JsonSchema {
|
|
65
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const configFile = process.argv[2]
|
|
69
|
+
const tuiFile = process.argv[3]
|
|
70
|
+
|
|
71
|
+
console.log(configFile)
|
|
72
|
+
await Bun.write(configFile, JSON.stringify(generateEffect(ConfigV1.Info), null, 2))
|
|
73
|
+
|
|
74
|
+
if (tuiFile) {
|
|
75
|
+
console.log(tuiFile)
|
|
76
|
+
await Bun.write(tuiFile, JSON.stringify(generateEffect(TuiConfig.Info), null, 2))
|
|
77
|
+
}
|