onlycode 1.18.0 → 1.20.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/bin/{opencode.cjs → onlycode.cjs} +8 -42
- package/package.json +12 -147
- package/src/account/account.ts +0 -463
- package/src/account/repo.ts +0 -173
- package/src/account/schema.ts +0 -99
- package/src/account/url.ts +0 -8
- package/src/acp/agent.ts +0 -95
- package/src/acp/config-option.ts +0 -203
- package/src/acp/content.ts +0 -250
- package/src/acp/directory.ts +0 -210
- package/src/acp/error.ts +0 -90
- package/src/acp/event.ts +0 -342
- package/src/acp/permission.ts +0 -124
- package/src/acp/profile.ts +0 -42
- package/src/acp/service.ts +0 -1048
- package/src/acp/session.ts +0 -231
- package/src/acp/tool.ts +0 -367
- package/src/acp/usage.ts +0 -232
- package/src/agent/agent.ts +0 -459
- package/src/agent/generate.txt +0 -75
- package/src/agent/prompt/compaction.txt +0 -9
- package/src/agent/prompt/explore.txt +0 -18
- package/src/agent/prompt/summary.txt +0 -11
- package/src/agent/prompt/title.txt +0 -44
- package/src/agent/subagent-permissions.ts +0 -27
- package/src/audio.d.ts +0 -14
- package/src/auth/index.ts +0 -99
- package/src/background/job.ts +0 -39
- package/src/bus/global.ts +0 -22
- package/src/cli/bootstrap.ts +0 -11
- package/src/cli/cmd/account.ts +0 -264
- package/src/cli/cmd/acp.ts +0 -73
- package/src/cli/cmd/agent.ts +0 -259
- package/src/cli/cmd/attach.ts +0 -97
- package/src/cli/cmd/cmd.ts +0 -7
- package/src/cli/cmd/db.ts +0 -62
- package/src/cli/cmd/debug/agent.handler.ts +0 -193
- package/src/cli/cmd/debug/agent.ts +0 -27
- package/src/cli/cmd/debug/config.ts +0 -14
- package/src/cli/cmd/debug/file.ts +0 -73
- package/src/cli/cmd/debug/index.ts +0 -87
- package/src/cli/cmd/debug/lsp.ts +0 -50
- package/src/cli/cmd/debug/ripgrep.ts +0 -79
- package/src/cli/cmd/debug/scrap.ts +0 -15
- package/src/cli/cmd/debug/skill.ts +0 -15
- package/src/cli/cmd/debug/snapshot.ts +0 -50
- package/src/cli/cmd/debug/startup.ts +0 -11
- package/src/cli/cmd/debug/v2.ts +0 -44
- package/src/cli/cmd/export.ts +0 -292
- package/src/cli/cmd/generate.ts +0 -54
- package/src/cli/cmd/github.handler.ts +0 -1593
- package/src/cli/cmd/github.shared.ts +0 -30
- package/src/cli/cmd/github.ts +0 -42
- package/src/cli/cmd/import.ts +0 -224
- package/src/cli/cmd/mcp.ts +0 -849
- package/src/cli/cmd/models.ts +0 -66
- package/src/cli/cmd/plug.ts +0 -230
- package/src/cli/cmd/pr.ts +0 -115
- package/src/cli/cmd/prompt-display.ts +0 -1
- package/src/cli/cmd/providers.ts +0 -534
- package/src/cli/cmd/run/demo.ts +0 -1274
- package/src/cli/cmd/run/entry.body.ts +0 -205
- package/src/cli/cmd/run/footer.command.tsx +0 -1064
- package/src/cli/cmd/run/footer.menu.tsx +0 -351
- package/src/cli/cmd/run/footer.permission.tsx +0 -472
- package/src/cli/cmd/run/footer.prompt.tsx +0 -1306
- package/src/cli/cmd/run/footer.question.tsx +0 -573
- package/src/cli/cmd/run/footer.subagent.tsx +0 -173
- package/src/cli/cmd/run/footer.ts +0 -1129
- package/src/cli/cmd/run/footer.view.tsx +0 -943
- package/src/cli/cmd/run/footer.width.ts +0 -27
- package/src/cli/cmd/run/permission.shared.ts +0 -256
- package/src/cli/cmd/run/prompt.editor.ts +0 -157
- package/src/cli/cmd/run/prompt.shared.ts +0 -153
- package/src/cli/cmd/run/question.shared.ts +0 -340
- package/src/cli/cmd/run/runtime.boot.ts +0 -202
- package/src/cli/cmd/run/runtime.lifecycle.ts +0 -406
- package/src/cli/cmd/run/runtime.queue.ts +0 -349
- package/src/cli/cmd/run/runtime.shared.ts +0 -17
- package/src/cli/cmd/run/runtime.stdin.ts +0 -37
- package/src/cli/cmd/run/runtime.ts +0 -814
- package/src/cli/cmd/run/scrollback.shared.ts +0 -92
- package/src/cli/cmd/run/scrollback.surface.ts +0 -431
- package/src/cli/cmd/run/scrollback.writer.tsx +0 -352
- package/src/cli/cmd/run/session-data.ts +0 -1113
- package/src/cli/cmd/run/session-replay.ts +0 -374
- package/src/cli/cmd/run/session.shared.ts +0 -196
- package/src/cli/cmd/run/splash.ts +0 -275
- package/src/cli/cmd/run/stream.transport.ts +0 -1462
- package/src/cli/cmd/run/stream.ts +0 -175
- package/src/cli/cmd/run/subagent-data.ts +0 -876
- package/src/cli/cmd/run/theme.ts +0 -690
- package/src/cli/cmd/run/tool.ts +0 -1489
- package/src/cli/cmd/run/trace.ts +0 -94
- package/src/cli/cmd/run/turn-summary.ts +0 -47
- package/src/cli/cmd/run/types.ts +0 -350
- package/src/cli/cmd/run/variant.shared.ts +0 -215
- package/src/cli/cmd/run.ts +0 -894
- package/src/cli/cmd/serve.ts +0 -24
- package/src/cli/cmd/session.ts +0 -147
- package/src/cli/cmd/stats.ts +0 -393
- package/src/cli/cmd/tui.ts +0 -224
- package/src/cli/cmd/uninstall.ts +0 -353
- package/src/cli/cmd/upgrade.ts +0 -74
- package/src/cli/cmd/web.ts +0 -84
- package/src/cli/effect/prompt.ts +0 -37
- package/src/cli/effect-cmd.ts +0 -96
- package/src/cli/error.ts +0 -130
- package/src/cli/heap.ts +0 -45
- package/src/cli/logo-pixel.ts +0 -35
- package/src/cli/logo.ts +0 -1
- package/src/cli/network.ts +0 -64
- package/src/cli/tui/layer.ts +0 -7
- package/src/cli/tui/validate-session.ts +0 -29
- package/src/cli/tui/worker.ts +0 -71
- package/src/cli/ui.ts +0 -148
- package/src/cli/upgrade.ts +0 -53
- package/src/command/index.ts +0 -184
- package/src/command/template/initialize.txt +0 -66
- package/src/command/template/review.txt +0 -101
- package/src/config/agent.ts +0 -59
- package/src/config/command.ts +0 -39
- package/src/config/config.ts +0 -686
- package/src/config/entry-name.ts +0 -19
- package/src/config/managed.ts +0 -69
- package/src/config/markdown.ts +0 -36
- package/src/config/parse.ts +0 -79
- package/src/config/paths.ts +0 -45
- package/src/config/plugin.ts +0 -79
- package/src/config/tui-cwd.ts +0 -5
- package/src/config/tui-host-attention.ts +0 -21
- package/src/config/tui-migrate.ts +0 -132
- package/src/config/tui.ts +0 -274
- package/src/config/variable.ts +0 -91
- package/src/control-plane/adapters/index.ts +0 -41
- package/src/control-plane/adapters/worktree.ts +0 -96
- package/src/control-plane/dev/README.md +0 -19
- package/src/control-plane/dev/debug-workspace-plugin.ts +0 -73
- package/src/control-plane/types.ts +0 -59
- package/src/control-plane/util.ts +0 -39
- package/src/control-plane/workspace-adapter-runtime.ts +0 -51
- package/src/control-plane/workspace-context.ts +0 -26
- package/src/control-plane/workspace.ts +0 -989
- package/src/effect/app-runtime.ts +0 -132
- package/src/effect/bootstrap-runtime.ts +0 -23
- package/src/effect/bridge.ts +0 -84
- package/src/effect/config-service.ts +0 -67
- package/src/effect/instance-ref.ts +0 -11
- package/src/effect/instance-registry.ts +0 -12
- package/src/effect/instance-state.ts +0 -69
- package/src/effect/promise.ts +0 -17
- package/src/effect/run-service.ts +0 -47
- package/src/effect/runner.ts +0 -217
- package/src/effect/runtime-flags.ts +0 -79
- package/src/env/index.ts +0 -43
- package/src/event-v2-bridge.ts +0 -79
- package/src/format/formatter.ts +0 -404
- package/src/format/index.ts +0 -205
- package/src/git/index.ts +0 -350
- package/src/id/id.ts +0 -80
- package/src/ide/index.ts +0 -61
- package/src/image/image.ts +0 -174
- package/src/index.ts +0 -142
- package/src/installation/index.ts +0 -350
- package/src/lsp/client.ts +0 -650
- package/src/lsp/diagnostic.ts +0 -29
- package/src/lsp/language.ts +0 -121
- package/src/lsp/launch.ts +0 -21
- package/src/lsp/lsp.ts +0 -511
- package/src/lsp/server.ts +0 -1983
- package/src/markdown.d.ts +0 -4
- package/src/mcp/auth.ts +0 -174
- package/src/mcp/catalog.ts +0 -153
- package/src/mcp/index.ts +0 -953
- package/src/mcp/oauth-callback.ts +0 -233
- package/src/mcp/oauth-provider.ts +0 -206
- package/src/node.ts +0 -4
- package/src/patch/index.ts +0 -686
- package/src/permission/arity.ts +0 -163
- package/src/permission/evaluate.ts +0 -1
- package/src/permission/index.ts +0 -230
- package/src/plugin/azure.ts +0 -26
- package/src/plugin/cloudflare.ts +0 -76
- package/src/plugin/digitalocean.ts +0 -383
- package/src/plugin/github-copilot/copilot.ts +0 -414
- package/src/plugin/github-copilot/models.ts +0 -246
- package/src/plugin/index.ts +0 -316
- package/src/plugin/install.ts +0 -439
- package/src/plugin/loader.ts +0 -237
- package/src/plugin/meta.ts +0 -188
- package/src/plugin/openai/README.md +0 -31
- package/src/plugin/openai/codex.ts +0 -641
- package/src/plugin/openai/ws-pool.ts +0 -270
- package/src/plugin/openai/ws.ts +0 -381
- package/src/plugin/pty-environment.ts +0 -24
- package/src/plugin/shared.ts +0 -323
- package/src/plugin/snowflake-cortex.ts +0 -529
- package/src/plugin/tui/internal.ts +0 -10
- package/src/plugin/tui/runtime.ts +0 -1130
- package/src/plugin/xai.ts +0 -716
- package/src/project/bootstrap-service.ts +0 -9
- package/src/project/bootstrap.ts +0 -76
- package/src/project/instance-context.ts +0 -24
- package/src/project/instance-layer.ts +0 -11
- package/src/project/instance-runtime.ts +0 -16
- package/src/project/instance-store.ts +0 -209
- package/src/project/project.ts +0 -519
- package/src/project/vcs.ts +0 -431
- package/src/provider/auth.ts +0 -233
- package/src/provider/error.ts +0 -188
- package/src/provider/model-status.ts +0 -8
- package/src/provider/provider.ts +0 -1975
- package/src/provider/transform.ts +0 -1543
- package/src/question/index.ts +0 -229
- package/src/question/schema.ts +0 -10
- package/src/server/auth.ts +0 -48
- package/src/server/event.ts +0 -13
- package/src/server/global-lifecycle.ts +0 -28
- package/src/server/init-projectors.ts +0 -3
- package/src/server/mdns.ts +0 -47
- package/src/server/projectors.ts +0 -1
- package/src/server/proxy-util.ts +0 -48
- package/src/server/routes/instance/httpapi/AGENTS.md +0 -39
- package/src/server/routes/instance/httpapi/api.ts +0 -78
- package/src/server/routes/instance/httpapi/errors.ts +0 -193
- package/src/server/routes/instance/httpapi/groups/config.ts +0 -65
- package/src/server/routes/instance/httpapi/groups/control-plane.ts +0 -35
- package/src/server/routes/instance/httpapi/groups/control.ts +0 -76
- package/src/server/routes/instance/httpapi/groups/event.ts +0 -29
- package/src/server/routes/instance/httpapi/groups/experimental.ts +0 -275
- package/src/server/routes/instance/httpapi/groups/file.ts +0 -185
- package/src/server/routes/instance/httpapi/groups/global.ts +0 -138
- package/src/server/routes/instance/httpapi/groups/instance.ts +0 -206
- package/src/server/routes/instance/httpapi/groups/mcp.ts +0 -156
- package/src/server/routes/instance/httpapi/groups/metadata.ts +0 -18
- package/src/server/routes/instance/httpapi/groups/permission.ts +0 -61
- package/src/server/routes/instance/httpapi/groups/project-copy.ts +0 -32
- package/src/server/routes/instance/httpapi/groups/project.ts +0 -93
- package/src/server/routes/instance/httpapi/groups/provider.ts +0 -101
- package/src/server/routes/instance/httpapi/groups/pty.ts +0 -172
- package/src/server/routes/instance/httpapi/groups/query.ts +0 -12
- package/src/server/routes/instance/httpapi/groups/question.ts +0 -74
- package/src/server/routes/instance/httpapi/groups/session.ts +0 -462
- package/src/server/routes/instance/httpapi/groups/sync.ts +0 -113
- package/src/server/routes/instance/httpapi/groups/tui.ts +0 -208
- package/src/server/routes/instance/httpapi/groups/workspace.ts +0 -141
- package/src/server/routes/instance/httpapi/handlers/config.ts +0 -34
- package/src/server/routes/instance/httpapi/handlers/control-plane.ts +0 -37
- package/src/server/routes/instance/httpapi/handlers/control.ts +0 -43
- package/src/server/routes/instance/httpapi/handlers/event.ts +0 -99
- package/src/server/routes/instance/httpapi/handlers/experimental.ts +0 -192
- package/src/server/routes/instance/httpapi/handlers/file.ts +0 -139
- package/src/server/routes/instance/httpapi/handlers/global.ts +0 -156
- package/src/server/routes/instance/httpapi/handlers/instance.ts +0 -110
- package/src/server/routes/instance/httpapi/handlers/mcp.ts +0 -111
- package/src/server/routes/instance/httpapi/handlers/permission.ts +0 -41
- package/src/server/routes/instance/httpapi/handlers/project-copy.ts +0 -83
- package/src/server/routes/instance/httpapi/handlers/project.ts +0 -63
- package/src/server/routes/instance/httpapi/handlers/provider.ts +0 -113
- package/src/server/routes/instance/httpapi/handlers/pty.ts +0 -273
- package/src/server/routes/instance/httpapi/handlers/question.ts +0 -54
- package/src/server/routes/instance/httpapi/handlers/session-errors.ts +0 -21
- package/src/server/routes/instance/httpapi/handlers/session.ts +0 -440
- package/src/server/routes/instance/httpapi/handlers/sync.ts +0 -89
- package/src/server/routes/instance/httpapi/handlers/tui.ts +0 -131
- package/src/server/routes/instance/httpapi/handlers/workspace.ts +0 -102
- package/src/server/routes/instance/httpapi/lifecycle.ts +0 -54
- package/src/server/routes/instance/httpapi/middleware/authorization.ts +0 -150
- package/src/server/routes/instance/httpapi/middleware/compression.ts +0 -64
- package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +0 -29
- package/src/server/routes/instance/httpapi/middleware/error.ts +0 -43
- package/src/server/routes/instance/httpapi/middleware/fence.ts +0 -25
- package/src/server/routes/instance/httpapi/middleware/instance-context.ts +0 -43
- package/src/server/routes/instance/httpapi/middleware/proxy.ts +0 -108
- package/src/server/routes/instance/httpapi/middleware/schema-error.ts +0 -41
- package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +0 -250
- package/src/server/routes/instance/httpapi/public.ts +0 -535
- package/src/server/routes/instance/httpapi/server.ts +0 -298
- package/src/server/routes/instance/httpapi/websocket-tracker.ts +0 -57
- package/src/server/server.ts +0 -225
- package/src/server/shared/fence.ts +0 -60
- package/src/server/shared/pty-ticket.ts +0 -15
- package/src/server/shared/public-ui.ts +0 -12
- package/src/server/shared/tui-control.ts +0 -28
- package/src/server/shared/ui.ts +0 -108
- package/src/server/shared/workspace-routing.ts +0 -38
- package/src/server/tui-event.ts +0 -53
- package/src/session/compaction.ts +0 -620
- package/src/session/instruction.ts +0 -241
- package/src/session/llm/AGENTS.md +0 -90
- package/src/session/llm/ai-sdk.ts +0 -288
- package/src/session/llm/native-request.ts +0 -196
- package/src/session/llm/native-runtime.ts +0 -195
- package/src/session/llm/request.ts +0 -216
- package/src/session/llm.ts +0 -415
- package/src/session/message-error.ts +0 -14
- package/src/session/message-v2.ts +0 -747
- package/src/session/message.ts +0 -148
- package/src/session/overflow.ts +0 -34
- package/src/session/processor.ts +0 -1084
- package/src/session/prompt/anthropic.txt +0 -109
- package/src/session/prompt/beast.txt +0 -151
- package/src/session/prompt/build-switch.txt +0 -9
- package/src/session/prompt/codex.txt +0 -83
- package/src/session/prompt/copilot-gpt-5.txt +0 -147
- package/src/session/prompt/default.txt +0 -99
- package/src/session/prompt/gemini.txt +0 -159
- package/src/session/prompt/gpt.txt +0 -111
- package/src/session/prompt/kimi.txt +0 -99
- package/src/session/prompt/plan-mode.txt +0 -74
- package/src/session/prompt/plan-reminder-anthropic.txt +0 -71
- package/src/session/prompt/plan.txt +0 -30
- package/src/session/prompt/trinity.txt +0 -101
- package/src/session/prompt.ts +0 -1707
- package/src/session/reminders.ts +0 -92
- package/src/session/retry.ts +0 -201
- package/src/session/revert.ts +0 -160
- package/src/session/run-state.ts +0 -156
- package/src/session/schema.ts +0 -26
- package/src/session/session.ts +0 -1119
- package/src/session/status.ts +0 -97
- package/src/session/summary.ts +0 -165
- package/src/session/system.ts +0 -117
- package/src/session/todo.ts +0 -90
- package/src/session/tools.ts +0 -207
- package/src/share/session.ts +0 -61
- package/src/share/share-next.ts +0 -385
- package/src/skill/discovery.ts +0 -109
- package/src/skill/index.ts +0 -366
- package/src/snapshot/index.ts +0 -808
- package/src/sql.d.ts +0 -4
- package/src/storage/schema.ts +0 -5
- package/src/storage/storage.ts +0 -329
- package/src/sync/README.md +0 -179
- package/src/sync/schema.ts +0 -11
- package/src/temporary.ts +0 -31
- package/src/tool/apply_patch.ts +0 -315
- package/src/tool/apply_patch.txt +0 -33
- package/src/tool/apply_patch.zh.txt +0 -33
- package/src/tool/description.ts +0 -100
- package/src/tool/edit.ts +0 -739
- package/src/tool/edit.txt +0 -10
- package/src/tool/edit.zh.txt +0 -10
- package/src/tool/external-directory.ts +0 -49
- package/src/tool/glob.ts +0 -78
- package/src/tool/glob.txt +0 -6
- package/src/tool/glob.zh.txt +0 -6
- package/src/tool/grep.ts +0 -114
- package/src/tool/grep.txt +0 -8
- package/src/tool/grep.zh.txt +0 -8
- package/src/tool/invalid.ts +0 -21
- package/src/tool/json-schema.ts +0 -164
- package/src/tool/lsp.ts +0 -115
- package/src/tool/lsp.txt +0 -24
- package/src/tool/lsp.zh.txt +0 -24
- package/src/tool/mcp-websearch.ts +0 -96
- package/src/tool/plan-enter.txt +0 -14
- package/src/tool/plan-enter.zh.txt +0 -14
- package/src/tool/plan-exit.txt +0 -13
- package/src/tool/plan-exit.zh.txt +0 -13
- package/src/tool/plan.ts +0 -81
- package/src/tool/question.ts +0 -46
- package/src/tool/question.txt +0 -10
- package/src/tool/question.zh.txt +0 -10
- package/src/tool/read.ts +0 -388
- package/src/tool/read.txt +0 -14
- package/src/tool/read.zh.txt +0 -14
- package/src/tool/registry.ts +0 -440
- package/src/tool/schema.ts +0 -14
- package/src/tool/shell/id.ts +0 -19
- package/src/tool/shell/prompt.ts +0 -307
- package/src/tool/shell/shell.txt +0 -21
- package/src/tool/shell.ts +0 -657
- package/src/tool/skill.ts +0 -73
- package/src/tool/skill.txt +0 -5
- package/src/tool/skill.zh.txt +0 -5
- package/src/tool/task.ts +0 -348
- package/src/tool/task.txt +0 -19
- package/src/tool/task.zh.txt +0 -19
- package/src/tool/todo.ts +0 -59
- package/src/tool/todowrite.txt +0 -44
- package/src/tool/todowrite.zh.txt +0 -44
- package/src/tool/tool.ts +0 -183
- package/src/tool/truncate.ts +0 -158
- package/src/tool/truncation-dir.ts +0 -4
- package/src/tool/webfetch.ts +0 -194
- package/src/tool/webfetch.txt +0 -13
- package/src/tool/webfetch.zh.txt +0 -13
- package/src/tool/websearch.ts +0 -145
- package/src/tool/websearch.txt +0 -14
- package/src/tool/websearch.zh.txt +0 -14
- package/src/tool/write.ts +0 -106
- package/src/tool/write.txt +0 -8
- package/src/tool/write.zh.txt +0 -8
- package/src/util/archive.ts +0 -17
- package/src/util/bom.ts +0 -27
- package/src/util/data-url.ts +0 -9
- package/src/util/defer.ts +0 -10
- package/src/util/effect-http-client.ts +0 -11
- package/src/util/error.ts +0 -1
- package/src/util/filesystem.ts +0 -251
- package/src/util/html.ts +0 -8
- package/src/util/iife.ts +0 -3
- package/src/util/lazy.ts +0 -20
- package/src/util/local-context.ts +0 -25
- package/src/util/locale.ts +0 -2
- package/src/util/media.ts +0 -26
- package/src/util/process.ts +0 -177
- package/src/util/proxy-env.ts +0 -72
- package/src/util/queue.ts +0 -32
- package/src/util/record.ts +0 -1
- package/src/util/repository.ts +0 -232
- package/src/util/rpc.ts +0 -66
- package/src/util/signal.ts +0 -12
- package/src/util/timeout.ts +0 -13
- package/src/util/token.ts +0 -1
- package/src/util/wildcard.ts +0 -59
- package/src/worktree/index.ts +0 -654
package/src/cli/cmd/run.ts
DELETED
|
@@ -1,894 +0,0 @@
|
|
|
1
|
-
import type { PermissionV1 } from "@opencode-ai/core/v1/permission"
|
|
2
|
-
// CLI entry point for `opencode run`.
|
|
3
|
-
//
|
|
4
|
-
// Handles three modes:
|
|
5
|
-
// 1. Non-interactive (default): sends a single prompt, streams events to
|
|
6
|
-
// stdout, and exits when the session goes idle.
|
|
7
|
-
// 2. Interactive local (`--interactive`): boots the split-footer direct mode
|
|
8
|
-
// with an in-process server (no external HTTP).
|
|
9
|
-
// 3. Interactive attach (`--interactive --attach`): connects to a running
|
|
10
|
-
// opencode server and runs interactive mode against it.
|
|
11
|
-
//
|
|
12
|
-
// Also supports `--command` for slash-command execution, `--format json` for
|
|
13
|
-
// raw event streaming, `--continue` / `--session` for session resumption,
|
|
14
|
-
// and `--fork` for forking before continuing.
|
|
15
|
-
import type { Argv } from "yargs"
|
|
16
|
-
import path from "path"
|
|
17
|
-
import { pathToFileURL } from "url"
|
|
18
|
-
import { Effect } from "effect"
|
|
19
|
-
import { UI } from "../ui"
|
|
20
|
-
import { effectCmd } from "../effect-cmd"
|
|
21
|
-
import { EOL } from "os"
|
|
22
|
-
import { Filesystem } from "@/util/filesystem"
|
|
23
|
-
import { createOpencodeClient, type OpencodeClient, type ToolPart } from "@opencode-ai/sdk/v2"
|
|
24
|
-
import { FormatError, FormatUnknownError } from "../error"
|
|
25
|
-
import { INTERACTIVE_INPUT_ERROR, resolveInteractiveStdin } from "./run/runtime.stdin"
|
|
26
|
-
|
|
27
|
-
type ModelInput = Parameters<OpencodeClient["session"]["prompt"]>[0]["model"]
|
|
28
|
-
|
|
29
|
-
function pick(value: string | undefined): ModelInput | undefined {
|
|
30
|
-
if (!value) return undefined
|
|
31
|
-
const [providerID, ...rest] = value.split("/")
|
|
32
|
-
return {
|
|
33
|
-
providerID,
|
|
34
|
-
modelID: rest.join("/"),
|
|
35
|
-
} as ModelInput
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function resolveRunInput(value?: string, piped?: string): string | undefined {
|
|
39
|
-
if (!value) {
|
|
40
|
-
return piped
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (!piped) {
|
|
44
|
-
return value
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return value + "\n" + piped
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
type FilePart = {
|
|
51
|
-
type: "file"
|
|
52
|
-
url: string
|
|
53
|
-
filename: string
|
|
54
|
-
mime: string
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type Inline = {
|
|
58
|
-
icon: string
|
|
59
|
-
title: string
|
|
60
|
-
description?: string
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
type SessionInfo = {
|
|
64
|
-
id: string
|
|
65
|
-
title?: string
|
|
66
|
-
directory?: string
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function inline(info: Inline) {
|
|
70
|
-
const suffix = info.description ? UI.Style.TEXT_DIM + ` ${info.description}` + UI.Style.TEXT_NORMAL : ""
|
|
71
|
-
UI.println(UI.Style.TEXT_NORMAL + info.icon, UI.Style.TEXT_NORMAL + info.title + suffix)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function block(info: Inline, output?: string) {
|
|
75
|
-
UI.empty()
|
|
76
|
-
inline(info)
|
|
77
|
-
if (!output?.trim()) return
|
|
78
|
-
UI.println(output)
|
|
79
|
-
UI.empty()
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function formatRunError(error: unknown) {
|
|
83
|
-
return FormatError(error) ?? FormatUnknownError(error)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async function tool(part: ToolPart) {
|
|
87
|
-
try {
|
|
88
|
-
const { toolInlineInfo } = await import("./run/tool")
|
|
89
|
-
const next = toolInlineInfo(part)
|
|
90
|
-
if (next.mode === "block") {
|
|
91
|
-
block(next, next.body)
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
inline(next)
|
|
96
|
-
} catch {
|
|
97
|
-
inline({
|
|
98
|
-
icon: "\u2699",
|
|
99
|
-
title: part.tool,
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async function toolError(part: ToolPart) {
|
|
105
|
-
try {
|
|
106
|
-
const { toolInlineInfo } = await import("./run/tool")
|
|
107
|
-
const next = toolInlineInfo(part)
|
|
108
|
-
inline({
|
|
109
|
-
icon: "✗",
|
|
110
|
-
title: `${next.title} failed`,
|
|
111
|
-
...(next.description && { description: next.description }),
|
|
112
|
-
})
|
|
113
|
-
return
|
|
114
|
-
} catch {
|
|
115
|
-
inline({
|
|
116
|
-
icon: "✗",
|
|
117
|
-
title: `${part.tool} failed`,
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export const RunCommand = effectCmd({
|
|
123
|
-
command: "run [message..]",
|
|
124
|
-
describe: "run opencode with a message",
|
|
125
|
-
// --attach connects to a remote server (no local instance needed); the
|
|
126
|
-
// default path runs an in-process server and needs the project instance.
|
|
127
|
-
instance: (args) => !args.attach,
|
|
128
|
-
// For --dir without --attach, load instance for the resolved target dir.
|
|
129
|
-
// The handler also chdirs (preserving the legacy order: chdir → file resolution).
|
|
130
|
-
directory: (args) => (args.dir && !args.attach ? path.resolve(process.cwd(), args.dir) : process.cwd()),
|
|
131
|
-
builder: (yargs: Argv) =>
|
|
132
|
-
yargs
|
|
133
|
-
.positional("message", {
|
|
134
|
-
describe: "message to send",
|
|
135
|
-
type: "string",
|
|
136
|
-
array: true,
|
|
137
|
-
default: [],
|
|
138
|
-
})
|
|
139
|
-
.option("command", {
|
|
140
|
-
describe: "the command to run, use message for args",
|
|
141
|
-
type: "string",
|
|
142
|
-
})
|
|
143
|
-
.option("continue", {
|
|
144
|
-
alias: ["c"],
|
|
145
|
-
describe: "continue the last session",
|
|
146
|
-
type: "boolean",
|
|
147
|
-
})
|
|
148
|
-
.option("session", {
|
|
149
|
-
alias: ["s"],
|
|
150
|
-
describe: "session id to continue",
|
|
151
|
-
type: "string",
|
|
152
|
-
})
|
|
153
|
-
.option("fork", {
|
|
154
|
-
describe: "fork the session before continuing (requires --continue or --session)",
|
|
155
|
-
type: "boolean",
|
|
156
|
-
})
|
|
157
|
-
.option("share", {
|
|
158
|
-
type: "boolean",
|
|
159
|
-
describe: "share the session",
|
|
160
|
-
})
|
|
161
|
-
.option("model", {
|
|
162
|
-
type: "string",
|
|
163
|
-
alias: ["m"],
|
|
164
|
-
describe: "model to use in the format of provider/model",
|
|
165
|
-
})
|
|
166
|
-
.option("agent", {
|
|
167
|
-
type: "string",
|
|
168
|
-
describe: "agent to use",
|
|
169
|
-
})
|
|
170
|
-
.option("format", {
|
|
171
|
-
type: "string",
|
|
172
|
-
choices: ["default", "json"],
|
|
173
|
-
default: "default",
|
|
174
|
-
describe: "format: default (formatted) or json (raw JSON events)",
|
|
175
|
-
})
|
|
176
|
-
.option("file", {
|
|
177
|
-
alias: ["f"],
|
|
178
|
-
type: "string",
|
|
179
|
-
array: true,
|
|
180
|
-
describe: "file(s) to attach to message",
|
|
181
|
-
})
|
|
182
|
-
.option("title", {
|
|
183
|
-
type: "string",
|
|
184
|
-
describe: "title for the session (uses truncated prompt if no value provided)",
|
|
185
|
-
})
|
|
186
|
-
.option("attach", {
|
|
187
|
-
type: "string",
|
|
188
|
-
describe: "attach to a running opencode server (e.g., http://localhost:4096)",
|
|
189
|
-
})
|
|
190
|
-
.option("password", {
|
|
191
|
-
alias: ["p"],
|
|
192
|
-
type: "string",
|
|
193
|
-
describe: "basic auth password (defaults to OPENCODE_SERVER_PASSWORD)",
|
|
194
|
-
})
|
|
195
|
-
.option("username", {
|
|
196
|
-
alias: ["u"],
|
|
197
|
-
type: "string",
|
|
198
|
-
describe: "basic auth username (defaults to OPENCODE_SERVER_USERNAME or 'opencode')",
|
|
199
|
-
})
|
|
200
|
-
.option("dir", {
|
|
201
|
-
type: "string",
|
|
202
|
-
describe: "directory to run in, path on remote server if attaching",
|
|
203
|
-
})
|
|
204
|
-
.option("port", {
|
|
205
|
-
type: "number",
|
|
206
|
-
describe: "port for the local server (defaults to random port if no value provided)",
|
|
207
|
-
})
|
|
208
|
-
.option("variant", {
|
|
209
|
-
type: "string",
|
|
210
|
-
describe: "model variant (provider-specific reasoning effort, e.g., high, max, minimal)",
|
|
211
|
-
})
|
|
212
|
-
.option("thinking", {
|
|
213
|
-
type: "boolean",
|
|
214
|
-
describe: "show thinking blocks",
|
|
215
|
-
})
|
|
216
|
-
.option("replay", {
|
|
217
|
-
type: "boolean",
|
|
218
|
-
default: true,
|
|
219
|
-
describe: "replay interactive session history on resume and after resize (use --no-replay to disable)",
|
|
220
|
-
})
|
|
221
|
-
.option("replay-limit", {
|
|
222
|
-
type: "number",
|
|
223
|
-
describe: "cap visible interactive replay to the newest N messages",
|
|
224
|
-
})
|
|
225
|
-
.option("interactive", {
|
|
226
|
-
alias: ["i"],
|
|
227
|
-
type: "boolean",
|
|
228
|
-
describe: "run in direct interactive split-footer mode",
|
|
229
|
-
default: false,
|
|
230
|
-
})
|
|
231
|
-
.option("dangerously-skip-permissions", {
|
|
232
|
-
type: "boolean",
|
|
233
|
-
describe: "auto-approve permissions that are not explicitly denied (dangerous!)",
|
|
234
|
-
default: false,
|
|
235
|
-
})
|
|
236
|
-
.option("demo", {
|
|
237
|
-
type: "boolean",
|
|
238
|
-
default: false,
|
|
239
|
-
describe: "enable direct interactive demo slash commands; pass one as the message to run it immediately",
|
|
240
|
-
}),
|
|
241
|
-
handler: Effect.fn("Cli.run")(function* (args) {
|
|
242
|
-
const { Agent } = yield* Effect.promise(() => import("@/agent/agent"))
|
|
243
|
-
const { RuntimeFlags } = yield* Effect.promise(() => import("@/effect/runtime-flags"))
|
|
244
|
-
const { InstanceRef } = yield* Effect.promise(() => import("@/effect/instance-ref"))
|
|
245
|
-
const { ServerAuth } = yield* Effect.promise(() => import("@/server/auth"))
|
|
246
|
-
const agentSvc = yield* Agent.Service
|
|
247
|
-
const flags = yield* RuntimeFlags.Service
|
|
248
|
-
const localInstance = yield* InstanceRef
|
|
249
|
-
yield* Effect.promise(async () => {
|
|
250
|
-
const rawMessage = [...args.message, ...(args["--"] || [])].join(" ")
|
|
251
|
-
const thinking = args.interactive ? (args.thinking ?? true) : (args.thinking ?? false)
|
|
252
|
-
const die = (message: string): never => {
|
|
253
|
-
UI.error(message)
|
|
254
|
-
process.exit(1)
|
|
255
|
-
}
|
|
256
|
-
const dieInteractive = (error: unknown): never => {
|
|
257
|
-
if (error instanceof Error && error.message === INTERACTIVE_INPUT_ERROR) {
|
|
258
|
-
die(error.message)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
throw error
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
let message = [...args.message, ...(args["--"] || [])]
|
|
265
|
-
.map((arg) => (arg.includes(" ") ? `"${arg.replace(/"/g, '\\"')}"` : arg))
|
|
266
|
-
.join(" ")
|
|
267
|
-
|
|
268
|
-
if (args.interactive && args.command) {
|
|
269
|
-
die("--interactive cannot be used with --command")
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (args.demo && !args.interactive) {
|
|
273
|
-
die("--demo requires --interactive")
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (args.interactive && args.format === "json") {
|
|
277
|
-
die("--interactive cannot be used with --format json")
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (args["replay-limit"] !== undefined && !args.interactive) {
|
|
281
|
-
die("--replay-limit requires --interactive")
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (
|
|
285
|
-
args["replay-limit"] !== undefined &&
|
|
286
|
-
(!Number.isInteger(args["replay-limit"]) || args["replay-limit"] <= 0)
|
|
287
|
-
) {
|
|
288
|
-
die("--replay-limit must be a positive integer")
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (args.interactive && !process.stdout.isTTY) {
|
|
292
|
-
die("--interactive requires a TTY stdout")
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (args.interactive) {
|
|
296
|
-
try {
|
|
297
|
-
resolveInteractiveStdin().cleanup?.()
|
|
298
|
-
} catch (error) {
|
|
299
|
-
dieInteractive(error)
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
const replay = args.replay || args["replay-limit"] !== undefined
|
|
304
|
-
|
|
305
|
-
const root = Filesystem.resolve(process.env.PWD ?? process.cwd())
|
|
306
|
-
const directory = (() => {
|
|
307
|
-
if (!args.dir) return args.attach ? undefined : root
|
|
308
|
-
if (args.attach) return args.dir
|
|
309
|
-
|
|
310
|
-
try {
|
|
311
|
-
process.chdir(path.isAbsolute(args.dir) ? args.dir : path.join(root, args.dir))
|
|
312
|
-
return process.cwd()
|
|
313
|
-
} catch {
|
|
314
|
-
UI.error("Failed to change directory to " + args.dir)
|
|
315
|
-
process.exit(1)
|
|
316
|
-
}
|
|
317
|
-
})()
|
|
318
|
-
const attachHeaders = args.attach
|
|
319
|
-
? ServerAuth.headers({ password: args.password, username: args.username })
|
|
320
|
-
: undefined
|
|
321
|
-
const attachSDK = (dir?: string) => {
|
|
322
|
-
return createOpencodeClient({
|
|
323
|
-
baseUrl: args.attach!,
|
|
324
|
-
directory: dir,
|
|
325
|
-
headers: attachHeaders,
|
|
326
|
-
})
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const files: FilePart[] = []
|
|
330
|
-
if (args.file) {
|
|
331
|
-
const list = Array.isArray(args.file) ? args.file : [args.file]
|
|
332
|
-
|
|
333
|
-
for (const filePath of list) {
|
|
334
|
-
const resolvedPath = path.resolve(args.attach ? root : (directory ?? root), filePath)
|
|
335
|
-
if (!(await Filesystem.exists(resolvedPath))) {
|
|
336
|
-
UI.error(`File not found: ${filePath}`)
|
|
337
|
-
process.exit(1)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const mime = (await Filesystem.isDir(resolvedPath)) ? "application/x-directory" : "text/plain"
|
|
341
|
-
|
|
342
|
-
files.push({
|
|
343
|
-
type: "file",
|
|
344
|
-
url: pathToFileURL(resolvedPath).href,
|
|
345
|
-
filename: path.basename(resolvedPath),
|
|
346
|
-
mime,
|
|
347
|
-
})
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const piped = process.stdin.isTTY ? undefined : await Bun.stdin.text()
|
|
352
|
-
message = resolveRunInput(message, piped) ?? ""
|
|
353
|
-
const initialInput = resolveRunInput(rawMessage, piped)
|
|
354
|
-
|
|
355
|
-
if (message.trim().length === 0 && !args.command && !args.interactive) {
|
|
356
|
-
UI.error("You must provide a message or a command")
|
|
357
|
-
process.exit(1)
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (args.fork && !args.continue && !args.session) {
|
|
361
|
-
UI.error("--fork requires --continue or --session")
|
|
362
|
-
process.exit(1)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const rules: PermissionV1.Ruleset = args.interactive
|
|
366
|
-
? []
|
|
367
|
-
: [
|
|
368
|
-
{
|
|
369
|
-
permission: "question",
|
|
370
|
-
action: "deny",
|
|
371
|
-
pattern: "*",
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
permission: "plan_enter",
|
|
375
|
-
action: "deny",
|
|
376
|
-
pattern: "*",
|
|
377
|
-
},
|
|
378
|
-
{
|
|
379
|
-
permission: "plan_exit",
|
|
380
|
-
action: "deny",
|
|
381
|
-
pattern: "*",
|
|
382
|
-
},
|
|
383
|
-
]
|
|
384
|
-
|
|
385
|
-
function title() {
|
|
386
|
-
if (args.title === undefined) return
|
|
387
|
-
if (args.title !== "") return args.title
|
|
388
|
-
return message.slice(0, 50) + (message.length > 50 ? "..." : "")
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
async function session(sdk: OpencodeClient): Promise<SessionInfo | undefined> {
|
|
392
|
-
if (args.session) {
|
|
393
|
-
const current = await sdk.session
|
|
394
|
-
.get({
|
|
395
|
-
sessionID: args.session,
|
|
396
|
-
})
|
|
397
|
-
.catch(() => undefined)
|
|
398
|
-
|
|
399
|
-
if (!current?.data) {
|
|
400
|
-
UI.error("Session not found")
|
|
401
|
-
process.exit(1)
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (args.fork) {
|
|
405
|
-
const forked = await sdk.session.fork({
|
|
406
|
-
sessionID: args.session,
|
|
407
|
-
})
|
|
408
|
-
const id = forked.data?.id
|
|
409
|
-
if (!id) {
|
|
410
|
-
return
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return {
|
|
414
|
-
id,
|
|
415
|
-
title: forked.data?.title ?? current.data.title,
|
|
416
|
-
directory: forked.data?.directory ?? current.data.directory,
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return {
|
|
421
|
-
id: current.data.id,
|
|
422
|
-
title: current.data.title,
|
|
423
|
-
directory: current.data.directory,
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const base = args.continue ? (await sdk.session.list()).data?.find((item) => !item.parentID) : undefined
|
|
428
|
-
|
|
429
|
-
if (base && args.fork) {
|
|
430
|
-
const forked = await sdk.session.fork({
|
|
431
|
-
sessionID: base.id,
|
|
432
|
-
})
|
|
433
|
-
const id = forked.data?.id
|
|
434
|
-
if (!id) {
|
|
435
|
-
return
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return {
|
|
439
|
-
id,
|
|
440
|
-
title: forked.data?.title ?? base.title,
|
|
441
|
-
directory: forked.data?.directory ?? base.directory,
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
if (base) {
|
|
446
|
-
return {
|
|
447
|
-
id: base.id,
|
|
448
|
-
title: base.title,
|
|
449
|
-
directory: base.directory,
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const name = title()
|
|
454
|
-
const result = await sdk.session.create({
|
|
455
|
-
title: name,
|
|
456
|
-
permission: [...rules],
|
|
457
|
-
})
|
|
458
|
-
const id = result.data?.id
|
|
459
|
-
if (!id) {
|
|
460
|
-
return
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
return {
|
|
464
|
-
id,
|
|
465
|
-
title: result.data?.title ?? name,
|
|
466
|
-
directory: result.data?.directory,
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
async function share(sdk: OpencodeClient, sessionID: string) {
|
|
471
|
-
const cfg = await sdk.config.get()
|
|
472
|
-
if (!cfg.data) return
|
|
473
|
-
if (cfg.data.share !== "auto" && !flags.autoShare && !args.share) return
|
|
474
|
-
const res = await sdk.session.share({ sessionID }).catch((error) => {
|
|
475
|
-
if (error instanceof Error && error.message.includes("disabled")) {
|
|
476
|
-
UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message)
|
|
477
|
-
}
|
|
478
|
-
return { error }
|
|
479
|
-
})
|
|
480
|
-
if (!res.error && "data" in res && res.data?.share?.url) {
|
|
481
|
-
UI.println(UI.Style.TEXT_INFO_BOLD + "~ " + res.data.share.url)
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
async function createFreshSession(
|
|
486
|
-
sdk: OpencodeClient,
|
|
487
|
-
input: { agent: string | undefined; model: ModelInput | undefined; variant: string | undefined },
|
|
488
|
-
): Promise<SessionInfo> {
|
|
489
|
-
const result = await sdk.session.create({
|
|
490
|
-
title: args.title !== undefined && args.title !== "" ? args.title : undefined,
|
|
491
|
-
agent: input.agent,
|
|
492
|
-
model: input.model
|
|
493
|
-
? {
|
|
494
|
-
providerID: input.model.providerID,
|
|
495
|
-
id: input.model.modelID,
|
|
496
|
-
variant: input.variant,
|
|
497
|
-
}
|
|
498
|
-
: undefined,
|
|
499
|
-
permission: [...rules],
|
|
500
|
-
})
|
|
501
|
-
const id = result.data?.id
|
|
502
|
-
if (!id) {
|
|
503
|
-
throw new Error("Failed to create session")
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
void share(sdk, id).catch(() => {})
|
|
507
|
-
return {
|
|
508
|
-
id,
|
|
509
|
-
title: result.data?.title,
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
async function current(sdk: OpencodeClient): Promise<string> {
|
|
514
|
-
if (!args.attach) {
|
|
515
|
-
return directory ?? root
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
const next = await sdk.path
|
|
519
|
-
.get()
|
|
520
|
-
.then((x) => x.data?.directory)
|
|
521
|
-
.catch(() => undefined)
|
|
522
|
-
if (next) {
|
|
523
|
-
return next
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
UI.error("Failed to resolve remote directory")
|
|
527
|
-
process.exit(1)
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
async function localAgent() {
|
|
531
|
-
if (!args.agent) return undefined
|
|
532
|
-
const name = args.agent
|
|
533
|
-
|
|
534
|
-
const entry = await Effect.runPromise(
|
|
535
|
-
agentSvc.get(name).pipe(Effect.provideService(InstanceRef, localInstance)),
|
|
536
|
-
)
|
|
537
|
-
if (!entry) {
|
|
538
|
-
UI.println(
|
|
539
|
-
UI.Style.TEXT_WARNING_BOLD + "!",
|
|
540
|
-
UI.Style.TEXT_NORMAL,
|
|
541
|
-
`agent "${name}" not found. Falling back to default agent`,
|
|
542
|
-
)
|
|
543
|
-
return undefined
|
|
544
|
-
}
|
|
545
|
-
if (entry.mode === "subagent") {
|
|
546
|
-
UI.println(
|
|
547
|
-
UI.Style.TEXT_WARNING_BOLD + "!",
|
|
548
|
-
UI.Style.TEXT_NORMAL,
|
|
549
|
-
`agent "${name}" is a subagent, not a primary agent. Falling back to default agent`,
|
|
550
|
-
)
|
|
551
|
-
return undefined
|
|
552
|
-
}
|
|
553
|
-
return name
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
async function attachAgent(sdk: OpencodeClient) {
|
|
557
|
-
if (!args.agent) return undefined
|
|
558
|
-
const name = args.agent
|
|
559
|
-
|
|
560
|
-
const modes = await sdk.app
|
|
561
|
-
.agents(undefined, { throwOnError: true })
|
|
562
|
-
.then((x) => x.data ?? [])
|
|
563
|
-
.catch(() => undefined)
|
|
564
|
-
|
|
565
|
-
if (!modes) {
|
|
566
|
-
UI.println(
|
|
567
|
-
UI.Style.TEXT_WARNING_BOLD + "!",
|
|
568
|
-
UI.Style.TEXT_NORMAL,
|
|
569
|
-
`failed to list agents from ${args.attach}. Falling back to default agent`,
|
|
570
|
-
)
|
|
571
|
-
return undefined
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
const agent = modes.find((a) => a.name === name)
|
|
575
|
-
if (!agent) {
|
|
576
|
-
UI.println(
|
|
577
|
-
UI.Style.TEXT_WARNING_BOLD + "!",
|
|
578
|
-
UI.Style.TEXT_NORMAL,
|
|
579
|
-
`agent "${name}" not found. Falling back to default agent`,
|
|
580
|
-
)
|
|
581
|
-
return undefined
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if (agent.mode === "subagent") {
|
|
585
|
-
UI.println(
|
|
586
|
-
UI.Style.TEXT_WARNING_BOLD + "!",
|
|
587
|
-
UI.Style.TEXT_NORMAL,
|
|
588
|
-
`agent "${name}" is a subagent, not a primary agent. Falling back to default agent`,
|
|
589
|
-
)
|
|
590
|
-
return undefined
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
return name
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
async function pickAgent(sdk: OpencodeClient) {
|
|
597
|
-
if (!args.agent) return undefined
|
|
598
|
-
if (args.attach) {
|
|
599
|
-
return attachAgent(sdk)
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
return localAgent()
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
async function execute(sdk: OpencodeClient) {
|
|
606
|
-
const sess = await session(sdk)
|
|
607
|
-
if (!sess?.id) {
|
|
608
|
-
UI.error("Session not found")
|
|
609
|
-
process.exit(1)
|
|
610
|
-
}
|
|
611
|
-
const sessionID = sess.id
|
|
612
|
-
|
|
613
|
-
function emit(type: string, data: Record<string, unknown>) {
|
|
614
|
-
if (args.format === "json") {
|
|
615
|
-
process.stdout.write(
|
|
616
|
-
JSON.stringify({
|
|
617
|
-
type,
|
|
618
|
-
timestamp: Date.now(),
|
|
619
|
-
sessionID,
|
|
620
|
-
...data,
|
|
621
|
-
}) + EOL,
|
|
622
|
-
)
|
|
623
|
-
return true
|
|
624
|
-
}
|
|
625
|
-
return false
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// Consume one subscribed event stream for the active session and mirror it
|
|
629
|
-
// to stdout/UI. `client` is passed explicitly because attach mode may
|
|
630
|
-
// rebind the SDK to the session's directory after the subscription is
|
|
631
|
-
// created, and replies issued from inside the loop must use that client.
|
|
632
|
-
async function loop(client: OpencodeClient, events: Awaited<ReturnType<typeof sdk.event.subscribe>>) {
|
|
633
|
-
const toggles = new Map<string, boolean>()
|
|
634
|
-
let error: string | undefined
|
|
635
|
-
|
|
636
|
-
for await (const event of events.stream) {
|
|
637
|
-
if (
|
|
638
|
-
event.type === "message.updated" &&
|
|
639
|
-
event.properties.sessionID === sessionID &&
|
|
640
|
-
event.properties.info.role === "assistant" &&
|
|
641
|
-
args.format !== "json" &&
|
|
642
|
-
toggles.get("start") !== true
|
|
643
|
-
) {
|
|
644
|
-
UI.empty()
|
|
645
|
-
UI.println(`> ${event.properties.info.agent} · ${event.properties.info.modelID}`)
|
|
646
|
-
UI.empty()
|
|
647
|
-
toggles.set("start", true)
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
if (event.type === "message.part.updated") {
|
|
651
|
-
const part = event.properties.part
|
|
652
|
-
if (part.sessionID !== sessionID) continue
|
|
653
|
-
|
|
654
|
-
if (part.type === "tool" && (part.state.status === "completed" || part.state.status === "error")) {
|
|
655
|
-
if (emit("tool_use", { part })) continue
|
|
656
|
-
if (part.state.status === "completed") {
|
|
657
|
-
await tool(part)
|
|
658
|
-
continue
|
|
659
|
-
}
|
|
660
|
-
await toolError(part)
|
|
661
|
-
UI.error(part.state.error)
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
if (
|
|
665
|
-
part.type === "tool" &&
|
|
666
|
-
part.tool === "task" &&
|
|
667
|
-
part.state.status === "running" &&
|
|
668
|
-
args.format !== "json"
|
|
669
|
-
) {
|
|
670
|
-
if (toggles.get(part.id) === true) continue
|
|
671
|
-
await tool(part)
|
|
672
|
-
toggles.set(part.id, true)
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
if (part.type === "step-start") {
|
|
676
|
-
if (emit("step_start", { part })) continue
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
if (part.type === "step-finish") {
|
|
680
|
-
if (emit("step_finish", { part })) continue
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
if (part.type === "text" && part.time?.end) {
|
|
684
|
-
if (emit("text", { part })) continue
|
|
685
|
-
const text = part.text.trim()
|
|
686
|
-
if (!text) continue
|
|
687
|
-
if (!process.stdout.isTTY) {
|
|
688
|
-
process.stdout.write(text + EOL)
|
|
689
|
-
continue
|
|
690
|
-
}
|
|
691
|
-
UI.empty()
|
|
692
|
-
UI.println(text)
|
|
693
|
-
UI.empty()
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
if (part.type === "reasoning" && part.time?.end && thinking) {
|
|
697
|
-
if (emit("reasoning", { part })) continue
|
|
698
|
-
const text = part.text.trim()
|
|
699
|
-
if (!text) continue
|
|
700
|
-
const line = `Thinking: ${text}`
|
|
701
|
-
if (process.stdout.isTTY) {
|
|
702
|
-
UI.empty()
|
|
703
|
-
UI.println(`${UI.Style.TEXT_DIM}\u001b[3m${line}\u001b[0m${UI.Style.TEXT_NORMAL}`)
|
|
704
|
-
UI.empty()
|
|
705
|
-
continue
|
|
706
|
-
}
|
|
707
|
-
process.stdout.write(line + EOL)
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
if (event.type === "session.error") {
|
|
712
|
-
const props = event.properties
|
|
713
|
-
if (props.sessionID !== sessionID || !props.error) continue
|
|
714
|
-
let err = String(props.error.name)
|
|
715
|
-
if ("data" in props.error && props.error.data && "message" in props.error.data) {
|
|
716
|
-
err = String(props.error.data.message)
|
|
717
|
-
}
|
|
718
|
-
error = error ? error + EOL + err : err
|
|
719
|
-
if (emit("error", { error: props.error })) continue
|
|
720
|
-
UI.error(err)
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
if (
|
|
724
|
-
event.type === "session.status" &&
|
|
725
|
-
event.properties.sessionID === sessionID &&
|
|
726
|
-
event.properties.status.type === "idle"
|
|
727
|
-
) {
|
|
728
|
-
break
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
if (event.type === "permission.asked") {
|
|
732
|
-
const permission = event.properties
|
|
733
|
-
if (permission.sessionID !== sessionID) continue
|
|
734
|
-
|
|
735
|
-
if (args["dangerously-skip-permissions"]) {
|
|
736
|
-
await client.permission.reply({
|
|
737
|
-
requestID: permission.id,
|
|
738
|
-
reply: "once",
|
|
739
|
-
})
|
|
740
|
-
} else {
|
|
741
|
-
UI.println(
|
|
742
|
-
UI.Style.TEXT_WARNING_BOLD + "!",
|
|
743
|
-
UI.Style.TEXT_NORMAL +
|
|
744
|
-
`permission requested: ${permission.permission} (${permission.patterns.join(", ")}); auto-rejecting`,
|
|
745
|
-
)
|
|
746
|
-
await client.permission.reply({
|
|
747
|
-
requestID: permission.id,
|
|
748
|
-
reply: "reject",
|
|
749
|
-
})
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
return error
|
|
754
|
-
}
|
|
755
|
-
const cwd = args.attach ? (directory ?? sess.directory ?? (await current(sdk))) : (directory ?? root)
|
|
756
|
-
const client = args.attach ? attachSDK(cwd) : sdk
|
|
757
|
-
|
|
758
|
-
// Validate agent if specified
|
|
759
|
-
const agent = await pickAgent(client)
|
|
760
|
-
|
|
761
|
-
await share(client, sessionID)
|
|
762
|
-
|
|
763
|
-
if (!args.interactive) {
|
|
764
|
-
const events = await client.event.subscribe()
|
|
765
|
-
const completed = loop(client, events).catch((e) => {
|
|
766
|
-
console.error(e)
|
|
767
|
-
process.exitCode = 1
|
|
768
|
-
})
|
|
769
|
-
async function finish() {
|
|
770
|
-
if (args.attach) return
|
|
771
|
-
const error = await completed
|
|
772
|
-
if (error) process.exitCode = 1
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
if (args.command) {
|
|
776
|
-
const result = await client.session.command({
|
|
777
|
-
sessionID,
|
|
778
|
-
agent,
|
|
779
|
-
model: args.model,
|
|
780
|
-
command: args.command,
|
|
781
|
-
arguments: message,
|
|
782
|
-
variant: args.variant,
|
|
783
|
-
})
|
|
784
|
-
if (result.error) {
|
|
785
|
-
if (!emit("error", { error: result.error })) UI.error(formatRunError(result.error))
|
|
786
|
-
process.exitCode = 1
|
|
787
|
-
return
|
|
788
|
-
}
|
|
789
|
-
await finish()
|
|
790
|
-
return
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
const model = pick(args.model)
|
|
794
|
-
const result = await client.session.prompt({
|
|
795
|
-
sessionID,
|
|
796
|
-
agent,
|
|
797
|
-
model,
|
|
798
|
-
variant: args.variant,
|
|
799
|
-
parts: [...files, { type: "text", text: message }],
|
|
800
|
-
})
|
|
801
|
-
if (result.error) {
|
|
802
|
-
if (!emit("error", { error: result.error })) UI.error(formatRunError(result.error))
|
|
803
|
-
process.exitCode = 1
|
|
804
|
-
return
|
|
805
|
-
}
|
|
806
|
-
await finish()
|
|
807
|
-
return
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
const model = pick(args.model)
|
|
811
|
-
const { runInteractiveMode } = await import("./run/runtime")
|
|
812
|
-
try {
|
|
813
|
-
await runInteractiveMode({
|
|
814
|
-
sdk: client,
|
|
815
|
-
directory: cwd,
|
|
816
|
-
sessionID,
|
|
817
|
-
sessionTitle: sess.title,
|
|
818
|
-
resume: Boolean(args.session || args.continue) && !args.fork,
|
|
819
|
-
replay,
|
|
820
|
-
replayLimit: args["replay-limit"],
|
|
821
|
-
agent,
|
|
822
|
-
model,
|
|
823
|
-
variant: args.variant,
|
|
824
|
-
files,
|
|
825
|
-
initialInput,
|
|
826
|
-
createSession: createFreshSession,
|
|
827
|
-
thinking,
|
|
828
|
-
backgroundSubagents: flags.experimentalBackgroundSubagents,
|
|
829
|
-
demo: args.demo,
|
|
830
|
-
})
|
|
831
|
-
} catch (error) {
|
|
832
|
-
dieInteractive(error)
|
|
833
|
-
}
|
|
834
|
-
return
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
if (args.interactive && !args.attach && !args.session && !args.continue) {
|
|
838
|
-
const model = pick(args.model)
|
|
839
|
-
const { runInteractiveLocalMode } = await import("./run/runtime")
|
|
840
|
-
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
841
|
-
const { Server } = await import("@/server/server")
|
|
842
|
-
const request = new Request(input, init)
|
|
843
|
-
const headers = new Headers(request.headers)
|
|
844
|
-
const auth = ServerAuth.header()
|
|
845
|
-
if (auth) headers.set("Authorization", auth)
|
|
846
|
-
return Server.Default().app.fetch(new Request(request, { headers }))
|
|
847
|
-
}) as typeof globalThis.fetch
|
|
848
|
-
|
|
849
|
-
try {
|
|
850
|
-
return await runInteractiveLocalMode({
|
|
851
|
-
directory: directory ?? root,
|
|
852
|
-
fetch: fetchFn,
|
|
853
|
-
resolveAgent: localAgent,
|
|
854
|
-
session,
|
|
855
|
-
share,
|
|
856
|
-
createSession: createFreshSession,
|
|
857
|
-
agent: args.agent,
|
|
858
|
-
model,
|
|
859
|
-
variant: args.variant,
|
|
860
|
-
replay,
|
|
861
|
-
replayLimit: args["replay-limit"],
|
|
862
|
-
files,
|
|
863
|
-
initialInput,
|
|
864
|
-
thinking,
|
|
865
|
-
backgroundSubagents: flags.experimentalBackgroundSubagents,
|
|
866
|
-
demo: args.demo,
|
|
867
|
-
})
|
|
868
|
-
} catch (error) {
|
|
869
|
-
dieInteractive(error)
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
if (args.attach) {
|
|
874
|
-
const sdk = attachSDK(directory)
|
|
875
|
-
return await execute(sdk)
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
879
|
-
const { Server } = await import("@/server/server")
|
|
880
|
-
const request = new Request(input, init)
|
|
881
|
-
const headers = new Headers(request.headers)
|
|
882
|
-
const auth = ServerAuth.header()
|
|
883
|
-
if (auth) headers.set("Authorization", auth)
|
|
884
|
-
return Server.Default().app.fetch(new Request(request, { headers }))
|
|
885
|
-
}) as typeof globalThis.fetch
|
|
886
|
-
const sdk = createOpencodeClient({
|
|
887
|
-
baseUrl: "http://opencode.internal",
|
|
888
|
-
fetch: fetchFn,
|
|
889
|
-
directory,
|
|
890
|
-
})
|
|
891
|
-
await execute(sdk)
|
|
892
|
-
})
|
|
893
|
-
}),
|
|
894
|
-
})
|