soraacode 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/soraacode.exe +10 -0
- package/package.json +17 -25
- package/{script/postinstall.mjs → postinstall.mjs} +5 -5
- package/AGENTS.md +0 -131
- package/Dockerfile +0 -18
- package/README.md +0 -15
- package/bin/opencode +0 -199
- package/bin/soraacode +0 -199
- package/bunfig.toml +0 -7
- package/git +0 -0
- package/migration/20260511173437_session-metadata/migration.sql +0 -1
- package/migration/20260511173437_session-metadata/snapshot.json +0 -1500
- package/parsers-config.ts +0 -1
- package/script/bench-search.ts +0 -94
- package/script/bench-test-suite.ts +0 -52
- package/script/build-headless.ts +0 -51
- package/script/build.ts +0 -245
- package/script/generate.ts +0 -14
- package/script/httpapi-exercise.ts +0 -1
- package/script/profile-test-files.ts +0 -42
- package/script/publish.ts +0 -213
- package/script/run-workspace-server +0 -106
- package/script/schema.ts +0 -77
- package/script/time.ts +0 -6
- package/script/trace-imports.ts +0 -153
- package/soraacode-0.1.7.tgz +0 -0
- package/specs/effect/error-boundaries-plan.md +0 -235
- package/specs/effect/errors.md +0 -207
- package/specs/effect/facades.md +0 -218
- package/specs/effect/guide.md +0 -247
- package/specs/effect/instance-context.md +0 -13
- package/specs/effect/loose-ends.md +0 -30
- package/specs/effect/migration.md +0 -62
- package/specs/effect/routes.md +0 -61
- package/specs/effect/schema.md +0 -88
- package/specs/effect/server-package.md +0 -58
- package/specs/effect/todo.md +0 -241
- package/specs/effect/tools.md +0 -88
- package/specs/openapi-translation-cleanup.md +0 -204
- package/specs/tui-plugins.md +0 -544
- package/specs/v2/api.ts +0 -67
- package/specs/v2/message-shape.md +0 -136
- package/specs/v2/notifications.md +0 -13
- package/specs/v2/tui-command-shim.md +0 -67
- package/src/account/account.ts +0 -481
- package/src/account/repo.ts +0 -171
- 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 -206
- package/src/acp/content.ts +0 -269
- package/src/acp/directory.ts +0 -212
- package/src/acp/error.ts +0 -97
- package/src/acp/event.ts +0 -421
- package/src/acp/permission.ts +0 -254
- package/src/acp/profile.ts +0 -42
- package/src/acp/service.ts +0 -1226
- package/src/acp/session.ts +0 -232
- package/src/acp/tool.ts +0 -364
- package/src/acp/usage.ts +0 -243
- package/src/agent/agent.ts +0 -450
- package/src/agent/generate.txt +0 -75
- package/src/agent/prompt/compaction.txt +0 -5
- 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 -97
- package/src/background/job.ts +0 -37
- package/src/bus/global.ts +0 -22
- package/src/cli/bootstrap.ts +0 -11
- package/src/cli/cmd/cmd.ts +0 -7
- package/src/cli/cmd/serve.ts +0 -24
- 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.ts +0 -2
- package/src/cli/network.ts +0 -80
- package/src/cli/ui.ts +0 -132
- package/src/command/index.ts +0 -177
- 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 -707
- 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 -61
- package/src/config/paths.ts +0 -45
- package/src/config/plugin.ts +0 -79
- package/src/config/v2-compat.ts +0 -449
- 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 -966
- package/src/effect/app-node-builder-v1.ts +0 -12
- package/src/effect/app-runtime.ts +0 -135
- package/src/effect/bootstrap-runtime.ts +0 -19
- 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 -78
- package/src/env/index.ts +0 -41
- package/src/event-manifest.ts +0 -3
- package/src/event-v2-bridge.ts +0 -71
- package/src/format/formatter.ts +0 -404
- package/src/format/index.ts +0 -203
- package/src/git/index.ts +0 -348
- package/src/id/id.ts +0 -80
- package/src/ide/index.ts +0 -54
- package/src/image/image.ts +0 -172
- package/src/index-headless.ts +0 -89
- package/src/index.ts +0 -93
- package/src/installation/index.ts +0 -336
- 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 -507
- package/src/lsp/server.ts +0 -1983
- package/src/markdown.d.ts +0 -4
- package/src/mcp/auth.ts +0 -163
- package/src/mcp/browser.ts +0 -37
- package/src/mcp/catalog.ts +0 -170
- package/src/mcp/index.ts +0 -1004
- package/src/mcp/oauth-callback.ts +0 -194
- package/src/mcp/oauth-provider.ts +0 -259
- 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 -223
- package/src/plugin/github-copilot/copilot.ts +0 -415
- package/src/plugin/github-copilot/models.ts +0 -261
- package/src/plugin/index.ts +0 -298
- 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 -575
- package/src/plugin/openai/ws-pool.ts +0 -271
- package/src/plugin/openai/ws.ts +0 -383
- package/src/plugin/pty-environment.ts +0 -24
- package/src/plugin/shared.ts +0 -323
- package/src/project/bootstrap-service.ts +0 -9
- package/src/project/bootstrap.ts +0 -58
- package/src/project/instance-context.ts +0 -24
- package/src/project/instance-runtime.ts +0 -16
- package/src/project/instance-store.ts +0 -213
- package/src/project/project.ts +0 -483
- package/src/project/vcs.ts +0 -423
- package/src/provider/auth.ts +0 -229
- package/src/provider/error.ts +0 -195
- package/src/provider/model-status.ts +0 -8
- package/src/provider/provider.ts +0 -1955
- package/src/provider/transform.ts +0 -1923
- package/src/question/index.ts +0 -161
- package/src/question/schema.ts +0 -4
- package/src/server/auth.ts +0 -48
- package/src/server/event.ts +0 -10
- package/src/server/global-lifecycle.ts +0 -28
- package/src/server/mdns.ts +0 -47
- 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 -97
- 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 -139
- 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 -193
- package/src/server/routes/instance/httpapi/handlers/file.ts +0 -139
- package/src/server/routes/instance/httpapi/handlers/global.ts +0 -126
- 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 -116
- 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 -442
- 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 -44
- 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 -131
- 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 -537
- package/src/server/routes/instance/httpapi/server.ts +0 -325
- package/src/server/routes/instance/httpapi/websocket-tracker.ts +0 -60
- package/src/server/server.ts +0 -224
- 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 -45
- package/src/server/tui-event.ts +0 -1
- package/src/session/compaction.ts +0 -608
- package/src/session/instruction.ts +0 -237
- package/src/session/llm/AGENTS.md +0 -90
- package/src/session/llm/ai-sdk.ts +0 -291
- 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 -226
- package/src/session/llm.ts +0 -390
- package/src/session/message-error.ts +0 -14
- package/src/session/message-v2.ts +0 -742
- package/src/session/message.ts +0 -148
- package/src/session/overflow.ts +0 -34
- package/src/session/processor.ts +0 -732
- package/src/session/prompt/build-switch.txt +0 -5
- package/src/session/prompt/default.txt +0 -35
- package/src/session/prompt/plan-mode.txt +0 -70
- package/src/session/prompt/plan.txt +0 -26
- package/src/session/prompt.ts +0 -1631
- package/src/session/reminders.ts +0 -92
- package/src/session/retry.ts +0 -209
- package/src/session/revert.ts +0 -136
- package/src/session/run-state.ts +0 -151
- package/src/session/schema.ts +0 -26
- package/src/session/session.ts +0 -1016
- package/src/session/status.ts +0 -56
- package/src/session/summary.ts +0 -160
- package/src/session/system.ts +0 -123
- package/src/session/todo.ts +0 -74
- package/src/session/tools.ts +0 -590
- package/src/share/session.ts +0 -58
- package/src/share/share-next.ts +0 -371
- package/src/skill/discovery.ts +0 -140
- package/src/skill/index.ts +0 -354
- package/src/snapshot/index.ts +0 -807
- package/src/sql.d.ts +0 -4
- package/src/storage/schema.ts +0 -5
- package/src/storage/storage.ts +0 -327
- 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 -313
- package/src/tool/apply_patch.txt +0 -14
- package/src/tool/code-mode.ts +0 -310
- package/src/tool/edit.ts +0 -737
- package/src/tool/edit.txt +0 -13
- package/src/tool/external-directory.ts +0 -49
- package/src/tool/glob.ts +0 -76
- package/src/tool/glob.txt +0 -7
- package/src/tool/grep.ts +0 -115
- package/src/tool/grep.txt +0 -7
- package/src/tool/invalid.ts +0 -21
- package/src/tool/json-schema.ts +0 -164
- package/src/tool/lsp.ts +0 -113
- package/src/tool/lsp.txt +0 -1
- package/src/tool/mcp-websearch.ts +0 -96
- package/src/tool/plan-enter.txt +0 -1
- package/src/tool/plan-exit.txt +0 -1
- package/src/tool/plan.ts +0 -79
- package/src/tool/question.ts +0 -44
- package/src/tool/question.txt +0 -1
- package/src/tool/read.ts +0 -386
- package/src/tool/read.txt +0 -13
- package/src/tool/registry.ts +0 -455
- package/src/tool/schema.ts +0 -14
- package/src/tool/shell/id.ts +0 -19
- package/src/tool/shell/prompt.ts +0 -293
- package/src/tool/shell/shell.txt +0 -21
- package/src/tool/shell.ts +0 -645
- package/src/tool/skill.ts +0 -70
- package/src/tool/skill.txt +0 -1
- package/src/tool/task.ts +0 -371
- package/src/tool/task.txt +0 -11
- package/src/tool/todo.ts +0 -46
- package/src/tool/todowrite.txt +0 -11
- package/src/tool/tool.ts +0 -183
- package/src/tool/truncate.ts +0 -156
- package/src/tool/truncation-dir.ts +0 -4
- package/src/tool/webfetch.ts +0 -192
- package/src/tool/webfetch.txt +0 -9
- package/src/tool/websearch.ts +0 -143
- package/src/tool/websearch.txt +0 -9
- package/src/tool/write.ts +0 -104
- package/src/tool/write.txt +0 -11
- 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 -16
- 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 -4
- 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 -3
- 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 -623
- package/sst-env.d.ts +0 -10
- package/tsconfig.headless.json +0 -13
- package/tsconfig.json +0 -16
package/src/tool/plan.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import path from "path"
|
|
2
|
-
import { SessionV1 } from "@soraacode/core/v1/session"
|
|
3
|
-
import { Effect, Schema } from "effect"
|
|
4
|
-
import * as Tool from "./tool"
|
|
5
|
-
import { Question } from "../question"
|
|
6
|
-
import { Session } from "@/session/session"
|
|
7
|
-
import { MessageV2 } from "../session/message-v2"
|
|
8
|
-
import { Provider } from "@/provider/provider"
|
|
9
|
-
import { InstanceState } from "@/effect/instance-state"
|
|
10
|
-
import { MessageID, PartID } from "../session/schema"
|
|
11
|
-
import EXIT_DESCRIPTION from "./plan-exit.txt"
|
|
12
|
-
|
|
13
|
-
export const Parameters = Schema.Struct({})
|
|
14
|
-
|
|
15
|
-
export const PlanExitTool = Tool.define(
|
|
16
|
-
"plan_exit",
|
|
17
|
-
Effect.gen(function* () {
|
|
18
|
-
const session = yield* Session.Service
|
|
19
|
-
const question = yield* Question.Service
|
|
20
|
-
const provider = yield* Provider.Service
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
description: EXIT_DESCRIPTION,
|
|
24
|
-
parameters: Parameters,
|
|
25
|
-
execute: (_params: {}, ctx: Tool.Context) =>
|
|
26
|
-
Effect.gen(function* () {
|
|
27
|
-
const instance = yield* InstanceState.context
|
|
28
|
-
const info = yield* session.get(ctx.sessionID)
|
|
29
|
-
const plan = path.relative(instance.worktree, Session.plan(info, instance))
|
|
30
|
-
const answers = yield* question.ask({
|
|
31
|
-
sessionID: ctx.sessionID,
|
|
32
|
-
questions: [
|
|
33
|
-
{
|
|
34
|
-
question: `Plan at ${plan} is complete. Would you like to switch to the build agent and start implementing?`,
|
|
35
|
-
header: "Build Agent",
|
|
36
|
-
custom: false,
|
|
37
|
-
options: [
|
|
38
|
-
{ label: "Yes", description: "Switch to build agent and start implementing the plan" },
|
|
39
|
-
{ label: "No", description: "Stay with plan agent to continue refining the plan" },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
tool: ctx.callID ? { messageID: ctx.messageID, callID: ctx.callID } : undefined,
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
if (answers[0]?.[0] === "No") yield* new Question.RejectedError()
|
|
47
|
-
|
|
48
|
-
const messages = yield* session.messages({ sessionID: ctx.sessionID }).pipe(Effect.orDie)
|
|
49
|
-
const lastUser = messages.findLast((item) => item.info.role === "user" && item.info.model)
|
|
50
|
-
const model =
|
|
51
|
-
lastUser?.info.role === "user" && lastUser.info.model ? lastUser.info.model : yield* provider.defaultModel()
|
|
52
|
-
|
|
53
|
-
const msg: SessionV1.User = {
|
|
54
|
-
id: MessageID.ascending(),
|
|
55
|
-
sessionID: ctx.sessionID,
|
|
56
|
-
role: "user",
|
|
57
|
-
time: { created: Date.now() },
|
|
58
|
-
agent: "build",
|
|
59
|
-
model,
|
|
60
|
-
}
|
|
61
|
-
yield* session.updateMessage(msg)
|
|
62
|
-
yield* session.updatePart({
|
|
63
|
-
id: PartID.ascending(),
|
|
64
|
-
messageID: msg.id,
|
|
65
|
-
sessionID: ctx.sessionID,
|
|
66
|
-
type: "text",
|
|
67
|
-
text: `The plan at ${plan} has been approved, you can now edit files. Execute the plan`,
|
|
68
|
-
synthetic: true,
|
|
69
|
-
} satisfies SessionV1.TextPart)
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
title: "Switching to build agent",
|
|
73
|
-
output: "User approved switching to build agent. Wait for further instructions.",
|
|
74
|
-
metadata: {},
|
|
75
|
-
}
|
|
76
|
-
}).pipe(Effect.orDie),
|
|
77
|
-
}
|
|
78
|
-
}),
|
|
79
|
-
)
|
package/src/tool/question.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect"
|
|
2
|
-
import * as Tool from "./tool"
|
|
3
|
-
import { Question } from "../question"
|
|
4
|
-
import DESCRIPTION from "./question.txt"
|
|
5
|
-
|
|
6
|
-
export const Parameters = Schema.Struct({
|
|
7
|
-
questions: Schema.mutable(Schema.Array(Question.Prompt)).annotate({ description: "Questions to ask" }),
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
type Metadata = {
|
|
11
|
-
answers: ReadonlyArray<Question.Answer>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const QuestionTool = Tool.define<typeof Parameters, Metadata, Question.Service>(
|
|
15
|
-
"question",
|
|
16
|
-
Effect.gen(function* () {
|
|
17
|
-
const question = yield* Question.Service
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
description: DESCRIPTION,
|
|
21
|
-
parameters: Parameters,
|
|
22
|
-
execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context<Metadata>) =>
|
|
23
|
-
Effect.gen(function* () {
|
|
24
|
-
const answers = yield* question.ask({
|
|
25
|
-
sessionID: ctx.sessionID,
|
|
26
|
-
questions: params.questions,
|
|
27
|
-
tool: ctx.callID ? { messageID: ctx.messageID, callID: ctx.callID } : undefined,
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const formatted = params.questions
|
|
31
|
-
.map((q, i) => `"${q.question}"="${answers[i]?.length ? answers[i].join(", ") : "Unanswered"}"`)
|
|
32
|
-
.join(", ")
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
title: `Asked ${params.questions.length} question${params.questions.length > 1 ? "s" : ""}`,
|
|
36
|
-
output: `User has answered your questions: ${formatted}. You can now continue with the user's answers in mind.`,
|
|
37
|
-
metadata: {
|
|
38
|
-
answers,
|
|
39
|
-
},
|
|
40
|
-
}
|
|
41
|
-
}).pipe(Effect.orDie),
|
|
42
|
-
}
|
|
43
|
-
}),
|
|
44
|
-
)
|
package/src/tool/question.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Ask the user for requirements, preferences, clarification, or implementation decisions. custom is enabled by default, so do not add an "Other" option. Use multiple: true for multi-select. If recommending an option, put it first and append (Recommended).
|
package/src/tool/read.ts
DELETED
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
import { Effect, Option, Schema, Scope, Stream } from "effect"
|
|
2
|
-
import { NonNegativeInt } from "@soraacode/core/schema"
|
|
3
|
-
import * as path from "path"
|
|
4
|
-
import * as Tool from "./tool"
|
|
5
|
-
import { FSUtil } from "@soraacode/core/fs-util"
|
|
6
|
-
import { LSP } from "@/lsp/lsp"
|
|
7
|
-
import DESCRIPTION from "./read.txt"
|
|
8
|
-
import { InstanceState } from "@/effect/instance-state"
|
|
9
|
-
import { assertExternalDirectoryEffect } from "./external-directory"
|
|
10
|
-
import { Instruction } from "../session/instruction"
|
|
11
|
-
import { isPdfAttachment, sniffAttachmentMime } from "@/util/media"
|
|
12
|
-
|
|
13
|
-
const DEFAULT_READ_LIMIT = 2000
|
|
14
|
-
const MAX_LINE_LENGTH = 2000
|
|
15
|
-
const MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`
|
|
16
|
-
const MAX_BYTES = 50 * 1024
|
|
17
|
-
const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`
|
|
18
|
-
const SAMPLE_BYTES = 4096
|
|
19
|
-
const SUPPORTED_IMAGE_MIMES = new Set(["image/jpeg", "image/png", "image/gif", "image/webp"])
|
|
20
|
-
|
|
21
|
-
class ReadStop extends Schema.TaggedErrorClass<ReadStop>()("ReadStop", {}) {}
|
|
22
|
-
|
|
23
|
-
// `offset` and `limit` were originally `z.coerce.number()` — the runtime
|
|
24
|
-
// coercion was useful when the tool was called from a shell but serves no
|
|
25
|
-
// purpose in the LLM tool-call path (the model emits typed JSON). The JSON
|
|
26
|
-
// Schema output is identical (`type: "number"`), so the LLM view is
|
|
27
|
-
// unchanged; purely CLI-facing uses must now send numbers rather than strings.
|
|
28
|
-
export const Parameters = Schema.Struct({
|
|
29
|
-
filePath: Schema.String.annotate({ description: "The absolute path to the file or directory to read" }),
|
|
30
|
-
offset: Schema.optional(NonNegativeInt).annotate({
|
|
31
|
-
description: "The line number to start reading from (1-indexed)",
|
|
32
|
-
}),
|
|
33
|
-
limit: Schema.optional(NonNegativeInt).annotate({
|
|
34
|
-
description: "The maximum number of lines to read (defaults to 2000)",
|
|
35
|
-
}),
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
type Display =
|
|
39
|
-
| {
|
|
40
|
-
type: "directory"
|
|
41
|
-
path: string
|
|
42
|
-
entries: string[]
|
|
43
|
-
offset: number
|
|
44
|
-
totalEntries: number
|
|
45
|
-
truncated: boolean
|
|
46
|
-
}
|
|
47
|
-
| {
|
|
48
|
-
type: "file"
|
|
49
|
-
path: string
|
|
50
|
-
text: string
|
|
51
|
-
lineStart: number
|
|
52
|
-
lineEnd: number
|
|
53
|
-
totalLines: number
|
|
54
|
-
truncated: boolean
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type Metadata = {
|
|
58
|
-
preview: string
|
|
59
|
-
truncated: boolean
|
|
60
|
-
loaded: string[]
|
|
61
|
-
display?: Display
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export const ReadTool = Tool.define<
|
|
65
|
-
typeof Parameters,
|
|
66
|
-
Metadata,
|
|
67
|
-
FSUtil.Service | Instruction.Service | LSP.Service | Scope.Scope
|
|
68
|
-
>(
|
|
69
|
-
"read",
|
|
70
|
-
Effect.gen(function* () {
|
|
71
|
-
const fs = yield* FSUtil.Service
|
|
72
|
-
const instruction = yield* Instruction.Service
|
|
73
|
-
const lsp = yield* LSP.Service
|
|
74
|
-
const scope = yield* Scope.Scope
|
|
75
|
-
|
|
76
|
-
const miss = Effect.fn("ReadTool.miss")(function* (filepath: string) {
|
|
77
|
-
const dir = path.dirname(filepath)
|
|
78
|
-
const base = path.basename(filepath)
|
|
79
|
-
const items = yield* fs.readDirectory(dir).pipe(
|
|
80
|
-
Effect.map((items) =>
|
|
81
|
-
items
|
|
82
|
-
.filter(
|
|
83
|
-
(item) =>
|
|
84
|
-
item.toLowerCase().includes(base.toLowerCase()) || base.toLowerCase().includes(item.toLowerCase()),
|
|
85
|
-
)
|
|
86
|
-
.map((item) => path.join(dir, item))
|
|
87
|
-
.slice(0, 3),
|
|
88
|
-
),
|
|
89
|
-
Effect.catch(() => Effect.succeed([] as string[])),
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
if (items.length > 0) {
|
|
93
|
-
return yield* Effect.fail(
|
|
94
|
-
new Error(`File not found: ${filepath}\n\nDid you mean one of these?\n${items.join("\n")}`),
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return yield* Effect.fail(new Error(`File not found: ${filepath}`))
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
const list = Effect.fn("ReadTool.list")(function* (filepath: string) {
|
|
102
|
-
const items = yield* fs.readDirectoryEntries(filepath)
|
|
103
|
-
return yield* Effect.forEach(
|
|
104
|
-
items,
|
|
105
|
-
Effect.fnUntraced(function* (item) {
|
|
106
|
-
if (item.type === "directory") return item.name + "/"
|
|
107
|
-
if (item.type !== "symlink") return item.name
|
|
108
|
-
|
|
109
|
-
const target = yield* fs.stat(path.join(filepath, item.name)).pipe(Effect.catch(() => Effect.void))
|
|
110
|
-
if (target?.type === "Directory") return item.name + "/"
|
|
111
|
-
return item.name
|
|
112
|
-
}),
|
|
113
|
-
{ concurrency: "unbounded" },
|
|
114
|
-
).pipe(Effect.map((items: string[]) => items.sort((a, b) => a.localeCompare(b))))
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
const warm = Effect.fn("ReadTool.warm")(function* (filepath: string) {
|
|
118
|
-
// LSP warm-up is optional; do not let a background defect fail an otherwise successful read.
|
|
119
|
-
yield* lsp.touchFile(filepath).pipe(Effect.ignoreCause, Effect.forkIn(scope))
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
const readSample = Effect.fn("ReadTool.readSample")(function* (
|
|
123
|
-
filepath: string,
|
|
124
|
-
fileSize: number,
|
|
125
|
-
sampleSize: number,
|
|
126
|
-
) {
|
|
127
|
-
if (fileSize === 0) return new Uint8Array()
|
|
128
|
-
|
|
129
|
-
return yield* Effect.scoped(
|
|
130
|
-
Effect.gen(function* () {
|
|
131
|
-
const file = yield* fs.open(filepath, { flag: "r" })
|
|
132
|
-
return Option.getOrElse(yield* file.readAlloc(Math.min(sampleSize, fileSize)), () => new Uint8Array())
|
|
133
|
-
}),
|
|
134
|
-
)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
const lines = Effect.fn("ReadTool.lines")(function* (filepath: string, opts: { limit: number; offset: number }) {
|
|
138
|
-
const start = opts.offset - 1
|
|
139
|
-
const raw: string[] = []
|
|
140
|
-
const flags = { bytes: 0, count: 0, cut: false, more: false, done: false }
|
|
141
|
-
|
|
142
|
-
// Note: prefer manual TextDecoder over Stream.decodeText — when the source stream
|
|
143
|
-
// ends without flushing, decodeText drops the final unterminated line. We also
|
|
144
|
-
// avoid Stream.runForEachWhile (it currently swallows the final unterminated
|
|
145
|
-
// line of the upstream splitLines pipeline) and use a tagged error to stop the
|
|
146
|
-
// upstream file stream as soon as the byte cap is reached.
|
|
147
|
-
const decoder = new TextDecoder("utf-8")
|
|
148
|
-
yield* fs.stream(filepath).pipe(
|
|
149
|
-
Stream.map((bytes) => decoder.decode(bytes, { stream: true })),
|
|
150
|
-
Stream.splitLines,
|
|
151
|
-
Stream.runForEach((text) =>
|
|
152
|
-
Effect.gen(function* () {
|
|
153
|
-
if (flags.done) return yield* new ReadStop()
|
|
154
|
-
flags.count += 1
|
|
155
|
-
if (flags.count <= start) return
|
|
156
|
-
|
|
157
|
-
if (raw.length >= opts.limit) {
|
|
158
|
-
flags.more = true
|
|
159
|
-
return
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const line = text.length > MAX_LINE_LENGTH ? text.substring(0, MAX_LINE_LENGTH) + MAX_LINE_SUFFIX : text
|
|
163
|
-
const size = Buffer.byteLength(line, "utf-8") + (raw.length > 0 ? 1 : 0)
|
|
164
|
-
if (flags.bytes + size <= MAX_BYTES) {
|
|
165
|
-
raw.push(line)
|
|
166
|
-
flags.bytes += size
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
flags.cut = true
|
|
171
|
-
flags.more = true
|
|
172
|
-
flags.done = true
|
|
173
|
-
return yield* new ReadStop()
|
|
174
|
-
}),
|
|
175
|
-
),
|
|
176
|
-
Effect.catchTag("ReadStop", () => Effect.void),
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
return { raw, count: flags.count, cut: flags.cut, more: flags.more, offset: opts.offset }
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
const isBinaryFile = (filepath: string, bytes: Uint8Array) => {
|
|
183
|
-
const ext = path.extname(filepath).toLowerCase()
|
|
184
|
-
switch (ext) {
|
|
185
|
-
case ".zip":
|
|
186
|
-
case ".tar":
|
|
187
|
-
case ".gz":
|
|
188
|
-
case ".exe":
|
|
189
|
-
case ".dll":
|
|
190
|
-
case ".so":
|
|
191
|
-
case ".class":
|
|
192
|
-
case ".jar":
|
|
193
|
-
case ".war":
|
|
194
|
-
case ".7z":
|
|
195
|
-
case ".doc":
|
|
196
|
-
case ".docx":
|
|
197
|
-
case ".xls":
|
|
198
|
-
case ".xlsx":
|
|
199
|
-
case ".ppt":
|
|
200
|
-
case ".pptx":
|
|
201
|
-
case ".odt":
|
|
202
|
-
case ".ods":
|
|
203
|
-
case ".odp":
|
|
204
|
-
case ".bin":
|
|
205
|
-
case ".dat":
|
|
206
|
-
case ".obj":
|
|
207
|
-
case ".o":
|
|
208
|
-
case ".a":
|
|
209
|
-
case ".lib":
|
|
210
|
-
case ".wasm":
|
|
211
|
-
case ".pyc":
|
|
212
|
-
case ".pyo":
|
|
213
|
-
return true
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (bytes.length === 0) return false
|
|
217
|
-
|
|
218
|
-
let nonPrintableCount = 0
|
|
219
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
220
|
-
if (bytes[i] === 0) return true
|
|
221
|
-
if (bytes[i] < 9 || (bytes[i] > 13 && bytes[i] < 32)) {
|
|
222
|
-
nonPrintableCount++
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return nonPrintableCount / bytes.length > 0.3
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const run = Effect.fn("ReadTool.execute")(function* (
|
|
230
|
-
params: Schema.Schema.Type<typeof Parameters>,
|
|
231
|
-
ctx: Tool.Context<Metadata>,
|
|
232
|
-
) {
|
|
233
|
-
const instance = yield* InstanceState.context
|
|
234
|
-
let filepath = params.filePath
|
|
235
|
-
if (!path.isAbsolute(filepath)) {
|
|
236
|
-
filepath = path.resolve(instance.directory, filepath)
|
|
237
|
-
}
|
|
238
|
-
if (process.platform === "win32") {
|
|
239
|
-
filepath = FSUtil.normalizePath(filepath)
|
|
240
|
-
}
|
|
241
|
-
const title = path.relative(instance.worktree, filepath)
|
|
242
|
-
|
|
243
|
-
const stat = yield* fs.stat(filepath).pipe(
|
|
244
|
-
Effect.catchIf(
|
|
245
|
-
(err) => "reason" in err && err.reason._tag === "NotFound",
|
|
246
|
-
() => Effect.succeed(undefined),
|
|
247
|
-
),
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
yield* assertExternalDirectoryEffect(ctx, filepath, {
|
|
251
|
-
bypass: Boolean(ctx.extra?.["bypassCwdCheck"]),
|
|
252
|
-
kind: stat?.type === "Directory" ? "directory" : "file",
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
yield* ctx.ask({
|
|
256
|
-
permission: "read",
|
|
257
|
-
patterns: [path.relative(instance.worktree, filepath)],
|
|
258
|
-
always: ["*"],
|
|
259
|
-
metadata: {},
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
if (!stat) return yield* miss(filepath)
|
|
263
|
-
|
|
264
|
-
if (stat.type === "Directory") {
|
|
265
|
-
const items = yield* list(filepath)
|
|
266
|
-
const limit = params.limit ?? DEFAULT_READ_LIMIT
|
|
267
|
-
const offset = params.offset || 1
|
|
268
|
-
const start = offset - 1
|
|
269
|
-
const sliced = items.slice(start, start + limit)
|
|
270
|
-
const truncated = start + sliced.length < items.length
|
|
271
|
-
|
|
272
|
-
return {
|
|
273
|
-
title,
|
|
274
|
-
output: [
|
|
275
|
-
`<path>${filepath}</path>`,
|
|
276
|
-
`<type>directory</type>`,
|
|
277
|
-
`<entries>`,
|
|
278
|
-
sliced.join("\n"),
|
|
279
|
-
truncated
|
|
280
|
-
? `\n(Showing ${sliced.length} of ${items.length} entries. Use 'offset' parameter to read beyond entry ${offset + sliced.length})`
|
|
281
|
-
: `\n(${items.length} entries)`,
|
|
282
|
-
`</entries>`,
|
|
283
|
-
].join("\n"),
|
|
284
|
-
metadata: {
|
|
285
|
-
preview: sliced.slice(0, 20).join("\n"),
|
|
286
|
-
truncated,
|
|
287
|
-
loaded: [] as string[],
|
|
288
|
-
display: {
|
|
289
|
-
type: "directory" as const,
|
|
290
|
-
path: filepath,
|
|
291
|
-
entries: sliced,
|
|
292
|
-
offset,
|
|
293
|
-
totalEntries: items.length,
|
|
294
|
-
truncated,
|
|
295
|
-
},
|
|
296
|
-
},
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const loaded = yield* instruction.resolve(ctx.messages, filepath, ctx.messageID)
|
|
301
|
-
const sample = yield* readSample(filepath, Number(stat.size), SAMPLE_BYTES)
|
|
302
|
-
|
|
303
|
-
const mime = sniffAttachmentMime(sample, FSUtil.mimeType(filepath))
|
|
304
|
-
const isImage = SUPPORTED_IMAGE_MIMES.has(mime)
|
|
305
|
-
|
|
306
|
-
if (isImage || isPdfAttachment(mime)) {
|
|
307
|
-
const bytes = yield* fs.readFile(filepath)
|
|
308
|
-
const msg = isPdfAttachment(mime) ? "PDF read successfully" : "Image read successfully"
|
|
309
|
-
return {
|
|
310
|
-
title,
|
|
311
|
-
output: msg,
|
|
312
|
-
metadata: {
|
|
313
|
-
preview: msg,
|
|
314
|
-
truncated: false,
|
|
315
|
-
loaded: loaded.map((item) => item.filepath),
|
|
316
|
-
},
|
|
317
|
-
attachments: [
|
|
318
|
-
{
|
|
319
|
-
type: "file" as const,
|
|
320
|
-
mime,
|
|
321
|
-
url: `data:${mime};base64,${Buffer.from(bytes).toString("base64")}`,
|
|
322
|
-
},
|
|
323
|
-
],
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (isBinaryFile(filepath, sample)) {
|
|
328
|
-
return yield* Effect.fail(new Error(`Cannot read binary file: ${filepath}`))
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const file = yield* lines(filepath, { limit: params.limit ?? DEFAULT_READ_LIMIT, offset: params.offset || 1 })
|
|
332
|
-
if (file.count < file.offset && !(file.count === 0 && file.offset === 1)) {
|
|
333
|
-
return yield* Effect.fail(
|
|
334
|
-
new Error(`Offset ${file.offset} is out of range for this file (${file.count} lines)`),
|
|
335
|
-
)
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
let output = [`<path>${filepath}</path>`, `<type>file</type>`, "<content>\n"].join("\n")
|
|
339
|
-
output += file.raw.map((line, i) => `${i + file.offset}: ${line}`).join("\n")
|
|
340
|
-
|
|
341
|
-
const last = file.offset + file.raw.length - 1
|
|
342
|
-
const next = last + 1
|
|
343
|
-
const truncated = file.more || file.cut
|
|
344
|
-
if (file.cut) {
|
|
345
|
-
output += `\n\n(Output capped at ${MAX_BYTES_LABEL}. Showing lines ${file.offset}-${last}. Use offset=${next} to continue.)`
|
|
346
|
-
} else if (file.more) {
|
|
347
|
-
output += `\n\n(Showing lines ${file.offset}-${last} of ${file.count}. Use offset=${next} to continue.)`
|
|
348
|
-
} else {
|
|
349
|
-
output += `\n\n(End of file - total ${file.count} lines)`
|
|
350
|
-
}
|
|
351
|
-
output += "\n</content>"
|
|
352
|
-
|
|
353
|
-
yield* warm(filepath)
|
|
354
|
-
|
|
355
|
-
if (loaded.length > 0) {
|
|
356
|
-
output += `\n\n<system-reminder>\n${loaded.map((item) => item.content).join("\n\n")}\n</system-reminder>`
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
return {
|
|
360
|
-
title,
|
|
361
|
-
output,
|
|
362
|
-
metadata: {
|
|
363
|
-
preview: file.raw.slice(0, 20).join("\n"),
|
|
364
|
-
truncated,
|
|
365
|
-
loaded: loaded.map((item) => item.filepath),
|
|
366
|
-
display: {
|
|
367
|
-
type: "file" as const,
|
|
368
|
-
path: filepath,
|
|
369
|
-
text: file.raw.join("\n"),
|
|
370
|
-
lineStart: file.offset,
|
|
371
|
-
lineEnd: last,
|
|
372
|
-
totalLines: file.count,
|
|
373
|
-
truncated,
|
|
374
|
-
},
|
|
375
|
-
},
|
|
376
|
-
}
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
return {
|
|
380
|
-
description: DESCRIPTION,
|
|
381
|
-
parameters: Parameters,
|
|
382
|
-
execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context<Metadata>) =>
|
|
383
|
-
run(params, ctx).pipe(Effect.orDie),
|
|
384
|
-
}
|
|
385
|
-
}),
|
|
386
|
-
)
|
package/src/tool/read.txt
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
Read files/directories using absolute paths.
|
|
2
|
-
|
|
3
|
-
Default: first 2000 lines.
|
|
4
|
-
|
|
5
|
-
Use offset for later sections.
|
|
6
|
-
|
|
7
|
-
Use grep for large-file content search and glob when the path is unknown.
|
|
8
|
-
|
|
9
|
-
Read multiple files in parallel.
|
|
10
|
-
|
|
11
|
-
Prefer larger windows over tiny slices.
|
|
12
|
-
|
|
13
|
-
Supports image/PDF attachments.
|